]> www.ginac.de Git - ginac.git/commitdiff
merging 1.2 branch into main trunk
authorChristian Bauer <Christian.Bauer@uni-mainz.de>
Wed, 2 Jul 2003 20:46:56 +0000 (20:46 +0000)
committerChristian Bauer <Christian.Bauer@uni-mainz.de>
Wed, 2 Jul 2003 20:46:56 +0000 (20:46 +0000)
144 files changed:
INSTALL
NEWS
check/Makefile.am
check/check_inifcns.cpp
check/check_lsolve.cpp
check/check_matrices.cpp
check/check_numeric.cpp
check/exam_archive.cpp
check/exam_clifford.cpp
check/exam_color.cpp
check/exam_differentiation.cpp
check/exam_indexed.cpp
check/exam_inifcns.cpp
check/exam_lsolve.cpp
check/exam_matrices.cpp
check/exam_misc.cpp
check/exam_normalization.cpp
check/exam_numeric.cpp
check/exam_paranoia.cpp
check/exam_polygcd.cpp
check/exam_powerlaws.cpp
check/exam_pseries.cpp
check/time_antipode.cpp
check/time_dennyfliegner.cpp
check/time_fateman_expand.cpp
check/time_gammaseries.cpp
check/time_lw_A.cpp
check/time_lw_B.cpp
check/time_lw_C.cpp
check/time_lw_D.cpp
check/time_lw_E.cpp
check/time_lw_F.cpp
check/time_lw_G.cpp
check/time_lw_H.cpp
check/time_lw_IJKL.cpp
check/time_lw_M1.cpp
check/time_lw_M2.cpp
check/time_lw_N.cpp
check/time_lw_O.cpp
check/time_lw_P.cpp
check/time_lw_Pprime.cpp
check/time_lw_Q.cpp
check/time_lw_Qprime.cpp
check/time_toeplitz.cpp
check/time_vandermonde.cpp
check/timer.cpp
check/timer.h [new file with mode: 0644]
check/times.h
configure.ac
debian/changelog
debian/control
debian/copyright
debian/docs [new file with mode: 0644]
debian/libginac-dev.postinst
debian/libginac1.1.dirs [moved from debian/dirs with 100% similarity]
debian/libginac1.1.files [new file with mode: 0644]
debian/postinst [deleted file]
debian/rules
debian/shlibs
doc/reference/DoxyfileHTML
doc/reference/DoxyfileTEX
doc/reference/Makefile.am
doc/tutorial/ginac.texi
ginac.m4
ginac/Makefile.am
ginac/add.cpp
ginac/add.h
ginac/archive.cpp
ginac/archive.h
ginac/basic.cpp
ginac/basic.h
ginac/clifford.cpp
ginac/clifford.h
ginac/color.cpp
ginac/color.h
ginac/constant.cpp
ginac/constant.h
ginac/container.h [new file with mode: 0644]
ginac/container.pl [deleted file]
ginac/ex.cpp
ginac/ex.h
ginac/expair.h
ginac/expairseq.cpp
ginac/expairseq.h
ginac/exprseq.cpp [moved from ginac/exprseq_suppl.cpp with 75% similarity]
ginac/exprseq.h [new file with mode: 0644]
ginac/fail.cpp
ginac/fail.h
ginac/fderivative.cpp
ginac/fderivative.h
ginac/flags.h
ginac/function.pl
ginac/idx.cpp
ginac/idx.h
ginac/indexed.cpp
ginac/indexed.h
ginac/inifcns.cpp
ginac/inifcns.h
ginac/inifcns_gamma.cpp
ginac/inifcns_trans.cpp
ginac/inifcns_zeta.cpp
ginac/input_lexer.h
ginac/input_parser.yy
ginac/lst.cpp [moved from ginac/lst_suppl.cpp with 79% similarity]
ginac/lst.h [new file with mode: 0644]
ginac/matrix.cpp
ginac/matrix.h
ginac/mul.cpp
ginac/mul.h
ginac/ncmul.cpp
ginac/ncmul.h
ginac/normal.cpp
ginac/numeric.cpp
ginac/numeric.h
ginac/operators.cpp
ginac/operators.h
ginac/power.cpp
ginac/power.h
ginac/print.cpp
ginac/print.h
ginac/pseries.cpp
ginac/pseries.h
ginac/ptr.h [new file with mode: 0644]
ginac/registrar.cpp
ginac/registrar.h
ginac/relational.cpp
ginac/relational.h
ginac/remember.cpp
ginac/remember.h
ginac/structure.cpp
ginac/structure.h
ginac/structure.pl [deleted file]
ginac/symbol.cpp
ginac/symbol.h
ginac/symmetry.cpp
ginac/symmetry.h
ginac/tensor.cpp
ginac/tensor.h
ginac/utils.cpp
ginac/utils.h
ginac/wildcard.cpp
ginac/wildcard.h
ginsh/ginsh_lexer.ll
ginsh/ginsh_parser.yy

diff --git a/INSTALL b/INSTALL
index 7c6258f3889723389732d7913c2cab8e3b229589..e1881a352da25f57fa739eedcc963ce0ef735cc7 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -6,11 +6,11 @@ one of the following FTP-sites:
   * <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
@@ -25,9 +25,10 @@ As with any autoconfiguring GNU software, installation is as easy as this:
  # 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:
@@ -67,8 +68,7 @@ Problems with CLN
 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
 ----------------------------
@@ -86,12 +86,4 @@ Problems with missing standard header files
 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.
diff --git a/NEWS b/NEWS
index d675dc1e22252652a6c0a5e6a6e2800068dbc929..13d6253997974a5f15a19d5bc4a05c11255653ed 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,12 +1,40 @@
 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
index bf25465c7ea83fe99ed664b3e8a0a6dfda10ff16..fcc2770adb0637c439a2b797e878bfa3870db9e8 100644 (file)
@@ -20,7 +20,7 @@ times_SOURCES = time_dennyfliegner.cpp time_gammaseries.cpp \
   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
index 3ba846108eba59177d0e9e0f64b418138ea5495e..81497cb9e0d1dabd2e939bee5c628b04d060e4d4 100644 (file)
@@ -24,7 +24,7 @@
 #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;
@@ -79,7 +79,7 @@ static unsigned inifcns_check_sin(void)
 }
 
 /* Simple tests on the cosine trigonometric function. */
-static unsigned inifcns_check_cos(void)
+static unsigned inifcns_check_cos()
 {
        unsigned result = 0;
        bool errorflag;
@@ -133,7 +133,7 @@ static unsigned inifcns_check_cos(void)
 }
 
 /* Simple tests on the tangent trigonometric function. */
-static unsigned inifcns_check_tan(void)
+static unsigned inifcns_check_tan()
 {
        unsigned result = 0;
        bool errorflag;
@@ -162,7 +162,7 @@ static unsigned inifcns_check_tan(void)
 }
 
 /* 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.
@@ -190,7 +190,7 @@ static unsigned inifcns_check_Li2(void)
        return result;
 }
 
-unsigned check_inifcns(void)
+unsigned check_inifcns()
 {
        unsigned result = 0;
 
index ac0574e48b6166d0ed1da8617b702164cc45c7e3..4c98fc510c5605454795a6d166e20fb508b041b2 100644 (file)
@@ -1,7 +1,8 @@
 /** @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
@@ -96,7 +97,7 @@ static unsigned check_inifcns_lsolve(unsigned n)
 {
        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;
@@ -155,7 +156,7 @@ static unsigned check_inifcns_lsolve(unsigned n)
        return result;
 }
 
-unsigned check_lsolve(void)
+unsigned check_lsolve()
 {
        unsigned result = 0;
        
@@ -163,23 +164,23 @@ unsigned check_lsolve(void)
        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;
        
index deb00471a8a0367867f1deb0eabcb56bf2063251..91f4b5da4b64ace42691890fbf614f9268d0a467 100644 (file)
@@ -1,6 +1,8 @@
 /** @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)
@@ -51,12 +53,12 @@ static unsigned integdom_matrix_determinants(void)
 
 /* 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:
@@ -85,12 +87,12 @@ static unsigned rational_matrix_determinants(void)
 }
 
 /* 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:
@@ -119,12 +121,12 @@ static unsigned funny_matrix_determinants(void)
 }
 
 /* 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) {
@@ -156,12 +158,12 @@ static unsigned compare_matrix_determinants(void)
        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) {
@@ -193,7 +195,7 @@ static unsigned symbolic_matrix_inverse(void)
        return result;
 }
 
-unsigned check_matrices(void)
+unsigned check_matrices()
 {
        unsigned result = 0;
        
index 47533029adef33bdeb12c55f9a64301a32b5b742..e67d6933009972243cf017d4f072f14ed1eeeed7 100644 (file)
@@ -25,7 +25,7 @@
 
 /* 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;
@@ -53,7 +53,7 @@ static unsigned check_numeric1(void)
        return result;
 }
 
-static unsigned check_numeric2(void)
+static unsigned check_numeric2()
 {
        unsigned result = 0;
        bool errorflag = false;
@@ -105,7 +105,7 @@ static unsigned check_numeric2(void)
        return result;
 }
 
-unsigned check_numeric(void)
+unsigned check_numeric()
 {
        unsigned result = 0;
        
index 6b787c05c66077e3cb5b326a8b1c6198a49549ae..0d6f1a6c9b9d6671d3eb9ee88ea8cbf0f89c910f 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <fstream>
 
-unsigned exam_archive(void)
+unsigned exam_archive()
 {
        unsigned result = 0;
        
index 25c815af507399178cc11fe434339f3a37c0c57c..aef55cbcac285e9c35799cfd93a7f8188d20d449 100644 (file)
@@ -44,7 +44,7 @@ static unsigned check_equal_simplify(const ex &e1, const ex &e2)
        return 0;
 }
 
-static unsigned clifford_check1(void)
+static unsigned clifford_check1()
 {
        // checks general identities and contractions
 
@@ -80,7 +80,7 @@ static unsigned clifford_check1(void)
        return result;
 }
 
-static unsigned clifford_check2(void)
+static unsigned clifford_check2()
 {
        // checks identities relating to gamma5
 
@@ -99,7 +99,7 @@ static unsigned clifford_check2(void)
        return result;
 }
 
-static unsigned clifford_check3(void)
+static unsigned clifford_check3()
 {
        // checks traces
 
@@ -187,7 +187,7 @@ static unsigned clifford_check3(void)
        return result;
 }
 
-static unsigned clifford_check4(void)
+static unsigned clifford_check4()
 {
        // simplify_indexed()/dirac_trace() cross-checks
 
@@ -221,7 +221,7 @@ static unsigned clifford_check4(void)
        return result;
 }
 
-static unsigned clifford_check5(void)
+static unsigned clifford_check5()
 {
        // canonicalize_clifford() checks
 
@@ -249,7 +249,7 @@ static unsigned clifford_check5(void)
        return result;
 }
 
-unsigned exam_clifford(void)
+unsigned exam_clifford()
 {
        unsigned result = 0;
        
index 558f654308e2f1887c590b1660fe48e6fbefda55..cbc99462ef676765d8a2501da44830972871a2ab 100644 (file)
@@ -44,7 +44,7 @@ static unsigned check_equal_simplify(const ex &e1, const ex &e2)
        return 0;
 }
 
-static unsigned color_check1(void)
+static unsigned color_check1()
 {
        // checks general identities and contractions of the structure constants
 
@@ -78,7 +78,7 @@ static unsigned color_check1(void)
        return result;
 }
 
-static unsigned color_check2(void)
+static unsigned color_check2()
 {
        // checks general identities and contractions of the generators
 
@@ -107,7 +107,7 @@ static unsigned color_check2(void)
        return result;
 }
 
-static unsigned color_check3(void)
+static unsigned color_check3()
 {
        // checks traces
 
@@ -128,7 +128,7 @@ static unsigned color_check3(void)
        return result;
 }
 
-unsigned exam_color(void)
+unsigned exam_color()
 {
        unsigned result = 0;
        
index 71923977a7f6176647071d6cfa7ba10ed5341514..33b13b1f05d3ccee9e82094d9425fc88b8505a23 100644 (file)
@@ -45,9 +45,7 @@ static unsigned check_diff(const ex &e, const symbol &x,
                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;
        }
@@ -55,7 +53,7 @@ static unsigned check_diff(const ex &e, const symbol &x,
 }
 
 // Simple (expanded) polynomials
-static unsigned exam_differentiation1(void)
+static unsigned exam_differentiation1()
 {
        unsigned result = 0;
        symbol x("x"), y("y");
@@ -86,7 +84,7 @@ static unsigned exam_differentiation1(void)
 }
 
 // Trigonometric functions
-static unsigned exam_differentiation2(void)
+static unsigned exam_differentiation2()
 {
        unsigned result = 0;
        symbol x("x"), y("y"), a("a"), b("b");
@@ -135,7 +133,7 @@ static unsigned exam_differentiation2(void)
 }
        
 // exp function
-static unsigned exam_differentiation3(void)
+static unsigned exam_differentiation3()
 {
        unsigned result = 0;
        symbol x("x"), y("y"), a("a"), b("b");
@@ -163,7 +161,7 @@ static unsigned exam_differentiation3(void)
 }
 
 // log functions
-static unsigned exam_differentiation4(void)
+static unsigned exam_differentiation4()
 {
        unsigned result = 0;
        symbol x("x"), y("y"), a("a"), b("b");
@@ -193,7 +191,7 @@ static unsigned exam_differentiation4(void)
 }
 
 // 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");
@@ -214,7 +212,7 @@ static unsigned exam_differentiation5(void)
 }
 
 // Series
-static unsigned exam_differentiation6(void)
+static unsigned exam_differentiation6()
 {
        symbol x("x");
        ex e, d, ed;
@@ -234,7 +232,7 @@ static unsigned exam_differentiation6(void)
 }
 
 // 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);
@@ -257,7 +255,7 @@ static unsigned exam_differentiation7(void)
        return 0;
 }
 
-unsigned exam_differentiation(void)
+unsigned exam_differentiation()
 {
        unsigned result = 0;
        
index 82a2539f9df6a86423a617495c68644a69fdd378..69816a74bcf81c34160d69fddf6a8b9344163340 100644 (file)
@@ -55,7 +55,7 @@ static unsigned check_equal_simplify(const ex &e1, const ex &e2, const scalar_pr
        return 0;
 }
 
-static unsigned delta_check(void)
+static unsigned delta_check()
 {
        // checks identities of the delta tensor
 
@@ -81,7 +81,7 @@ static unsigned delta_check(void)
        return result;
 }
 
-static unsigned metric_check(void)
+static unsigned metric_check()
 {
        // checks identities of the metric tensor
 
@@ -114,7 +114,7 @@ static unsigned metric_check(void)
        return result;
 }
 
-static unsigned epsilon_check(void)
+static unsigned epsilon_check()
 {
        // checks identities of the epsilon tensor
 
@@ -153,7 +153,7 @@ REGISTER_FUNCTION(symm_fcn, set_symmetry(sy_symm(0, 1)));
 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
 
@@ -202,7 +202,7 @@ static unsigned symmetry_check(void)
        return result;
 }
 
-static unsigned scalar_product_check(void)
+static unsigned scalar_product_check()
 {
        // check scalar product replacement
 
@@ -225,7 +225,7 @@ static unsigned scalar_product_check(void)
        return result;
 }
 
-static unsigned edyn_check(void)
+static unsigned edyn_check()
 {
        // Relativistic electrodynamics
 
@@ -312,7 +312,7 @@ static unsigned edyn_check(void)
        return result;
 }
 
-static unsigned spinor_check(void)
+static unsigned spinor_check()
 {
        // check identities of the spinor metric
 
@@ -347,7 +347,7 @@ static unsigned spinor_check(void)
        return result;
 }
 
-static unsigned dummy_check(void)
+static unsigned dummy_check()
 {
        // check dummy index renaming/repositioning
 
@@ -380,7 +380,7 @@ static unsigned dummy_check(void)
        return result;
 }
 
-unsigned exam_indexed(void)
+unsigned exam_indexed()
 {
        unsigned result = 0;
        
index 1291030a3827fa549eceb87abb1702082511a458..a3a09650cd809f6020f820a0b7d99857b5c05382 100644 (file)
@@ -24,7 +24,7 @@
 #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");
@@ -116,7 +116,7 @@ static unsigned inifcns_consist_trans(void)
 
 /* 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;
@@ -161,7 +161,7 @@ static unsigned inifcns_consist_gamma(void)
 
 /* 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;
@@ -183,7 +183,7 @@ static unsigned inifcns_consist_psi(void)
 /* 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;
@@ -208,7 +208,7 @@ static unsigned inifcns_consist_zeta(void)
        return result;
 }
 
-unsigned exam_inifcns(void)
+unsigned exam_inifcns()
 {
        unsigned result = 0;
        
index 1321a71572a0fb6796adc044a561166fd2dc8715..ff510b314dde61623ef9bef397a99fcda6b9fc50 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "exams.h"
 
-static unsigned exam_lsolve1(void)
+static unsigned exam_lsolve1()
 {
        // A trivial example.
        unsigned result = 0;
@@ -40,7 +40,7 @@ static unsigned exam_lsolve1(void)
        return result;
 }
 
-static unsigned exam_lsolve2a(void)
+static unsigned exam_lsolve2a()
 {
        // An example from the Maple online help.
        unsigned result = 0;
@@ -68,7 +68,7 @@ static unsigned exam_lsolve2a(void)
        return result;
 }
 
-static unsigned exam_lsolve2b(void)
+static unsigned exam_lsolve2b()
 {
        // A boring example from Mathematica's online help.
        unsigned result = 0;
@@ -96,7 +96,7 @@ static unsigned exam_lsolve2b(void)
        return result;
 }
 
-static unsigned exam_lsolve2c(void)
+static unsigned exam_lsolve2c()
 {
        // A more interesting example from the Maple online help.
        unsigned result = 0;
@@ -124,7 +124,7 @@ static unsigned exam_lsolve2c(void)
        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;
@@ -152,7 +152,7 @@ static unsigned exam_lsolve2S(void)
        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;
@@ -183,7 +183,7 @@ static unsigned exam_lsolve3S(void)
        return result;
 }
 
-unsigned exam_lsolve(void)
+unsigned exam_lsolve()
 {
        unsigned result = 0;
        
index 867f52c9ebcab57ffb106f53c7367c8e40d8f34c..9a88c8c2bc80af55f7f3197ade0828280d8f465f 100644 (file)
@@ -23,7 +23,7 @@
 #include <stdexcept>
 #include "exams.h"
 
-static unsigned matrix_determinants(void)
+static unsigned matrix_determinants()
 {
        unsigned result = 0;
        ex det;
@@ -110,7 +110,7 @@ static unsigned matrix_determinants(void)
        return result;
 }
 
-static unsigned matrix_invert1(void)
+static unsigned matrix_invert1()
 {
        unsigned result = 0;
        matrix m(1,1);
@@ -128,7 +128,7 @@ static unsigned matrix_invert1(void)
        return result;
 }
 
-static unsigned matrix_invert2(void)
+static unsigned matrix_invert2()
 {
        unsigned result = 0;
        matrix m(2,2);
@@ -150,7 +150,7 @@ static unsigned matrix_invert2(void)
        return result;
 }
 
-static unsigned matrix_invert3(void)
+static unsigned matrix_invert3()
 {
        unsigned result = 0;
        matrix m(3,3);
@@ -180,7 +180,7 @@ static unsigned matrix_invert3(void)
        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 ]
@@ -216,7 +216,7 @@ static unsigned matrix_solve2(void)
        return result;
 }
 
-static unsigned matrix_evalm(void)
+static unsigned matrix_evalm()
 {
        unsigned result = 0;
 
@@ -241,7 +241,7 @@ static unsigned matrix_evalm(void)
        return result;
 }
 
-static unsigned matrix_misc(void)
+static unsigned matrix_misc()
 {
        unsigned result = 0;
        matrix m1(2,2);
@@ -292,7 +292,7 @@ static unsigned matrix_misc(void)
        return result;
 }
 
-unsigned exam_matrices(void)
+unsigned exam_matrices()
 {
        unsigned result = 0;
        
index 1da10b784e2a75ab9bf551e6d695fd5dfa366e71..4127a32710f59b6b9c3919e0336dc20de3d2f111 100644 (file)
@@ -24,7 +24,7 @@
 #include "exams.h"
 
 #define VECSIZE 30
-static unsigned exam_expand_subs(void)
+static unsigned exam_expand_subs()
 {
        unsigned result = 0;
        symbol a[VECSIZE];
@@ -51,7 +51,7 @@ static unsigned exam_expand_subs(void)
  *  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");
@@ -69,7 +69,7 @@ static unsigned exam_expand_subs2(void)
        return result;
 }
 
-static unsigned exam_expand_power(void)
+static unsigned exam_expand_power()
 {
        unsigned result = 0;
        symbol x("x"), a("a"), b("b");
@@ -86,7 +86,7 @@ static unsigned exam_expand_power(void)
        return result;
 }
 
-static unsigned exam_sqrfree(void)
+static unsigned exam_sqrfree()
 {
        unsigned result = 0;
        symbol x("x"), y("y");
@@ -133,7 +133,7 @@ static unsigned exam_sqrfree(void)
  * 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;
@@ -200,7 +200,7 @@ static unsigned exam_operator_semantics(void)
 }
 
 /* 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");
@@ -226,7 +226,45 @@ static unsigned exam_subs(void)
        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;
        
@@ -239,6 +277,8 @@ unsigned exam_misc(void)
        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;
index 02f2a8217fc889b723749754ea0fd148cd4fc176..0aafa4999437ef695ecf92d5685445c5fc14bac3 100644 (file)
@@ -35,7 +35,7 @@ static unsigned check_normal(const ex &e, const ex &d)
        return 0;
 }
 
-static unsigned exam_normal1(void)
+static unsigned exam_normal1()
 {
        unsigned result = 0;
        ex e, d;
@@ -62,7 +62,7 @@ static unsigned exam_normal1(void)
        return result;
 }
 
-static unsigned exam_normal2(void)
+static unsigned exam_normal2()
 {
        unsigned result = 0;
        ex e, d;
@@ -101,7 +101,7 @@ static unsigned exam_normal2(void)
        return result;
 }
 
-static unsigned exam_normal3(void)
+static unsigned exam_normal3()
 {
        unsigned result = 0;
        ex e, d;
@@ -124,7 +124,7 @@ static unsigned exam_normal3(void)
        return result;
 }
 
-static unsigned exam_normal4(void)
+static unsigned exam_normal4()
 {
        unsigned result = 0;
        ex e, d;
@@ -157,7 +157,7 @@ static unsigned exam_normal4(void)
        return result;
 }
 
-unsigned exam_normalization(void)
+unsigned exam_normalization()
 {
        unsigned result = 0;
        
index 3b943b17e41f359381fd26575c74a3ea5bb15ef9..90e435e8f53f03243ee9723325f848f269012b64 100644 (file)
@@ -27,7 +27,7 @@
 
 /* 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);
@@ -112,7 +112,7 @@ static unsigned exam_numeric1(void)
  * 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;
        
@@ -151,7 +151,7 @@ static unsigned exam_numeric2(void)
 
 /* 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;
@@ -269,7 +269,7 @@ static unsigned exam_numeric3(void)
 
 /* 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;
@@ -300,7 +300,7 @@ static unsigned exam_numeric4(void)
 
 /* 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;
        
@@ -319,7 +319,7 @@ static unsigned exam_numeric5(void)
 
 /* This test checks whether the numeric output/parsing routines are
    consistent. */
-static unsigned exam_numeric6(void)
+static unsigned exam_numeric6()
 {
        unsigned result = 0;
 
@@ -373,7 +373,7 @@ static unsigned exam_numeric6(void)
        return result;
 }
 
-unsigned exam_numeric(void)
+unsigned exam_numeric()
 {
        unsigned result = 0;
        
index 4050b5f5c238fcd49594993c4d18f02ce18ecdc1..c1df502c9282282311ee536513d326219c23be96 100644 (file)
@@ -28,7 +28,7 @@
 // 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");
@@ -59,7 +59,7 @@ static unsigned exam_paranoia1(void)
 // 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");
@@ -95,7 +95,7 @@ static unsigned exam_paranoia2(void)
 // 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");
@@ -124,7 +124,7 @@ static unsigned exam_paranoia3(void)
 }
 
 // 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");
@@ -149,7 +149,7 @@ static unsigned exam_paranoia4(void)
 }
 
 // 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");
@@ -168,7 +168,7 @@ static unsigned exam_paranoia5(void)
 }
 
 // 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");
@@ -186,7 +186,7 @@ static unsigned exam_paranoia6(void)
 
 // 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");
@@ -206,7 +206,7 @@ static unsigned exam_paranoia7(void)
 // 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");
@@ -232,7 +232,7 @@ static unsigned exam_paranoia8(void)
 // 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");
@@ -251,7 +251,7 @@ static unsigned exam_paranoia9(void)
 // 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;
        
@@ -276,7 +276,7 @@ static unsigned exam_paranoia10(void)
 // 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");
@@ -295,7 +295,7 @@ static unsigned exam_paranoia11(void)
 // 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");
@@ -314,7 +314,7 @@ static unsigned exam_paranoia12(void)
 
 // 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");
@@ -338,7 +338,7 @@ static unsigned exam_paranoia13(void)
 
 // 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");
@@ -354,7 +354,7 @@ static unsigned exam_paranoia14(void)
 
 // 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;
 
@@ -370,7 +370,7 @@ static unsigned exam_paranoia15(void)
        return result;
 }
 
-unsigned exam_paranoia(void)
+unsigned exam_paranoia()
 {
        unsigned result = 0;
        
index e350579b8bfbca421a345494f8b96ac6f284f19d..4b8bd440d0a98eec71bcd81b3eb75c151779b92f 100644 (file)
@@ -29,7 +29,7 @@ static symbol x("x"), z("z");
 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;
@@ -51,7 +51,7 @@ static unsigned poly_gcd1(void)
 }
 
 // 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;
@@ -74,7 +74,7 @@ static unsigned poly_gcd2(void)
 }
 
 // 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);
@@ -94,7 +94,7 @@ static unsigned poly_gcd3(void)
 }
 
 // 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);
@@ -117,7 +117,7 @@ static unsigned poly_gcd3p(void)
 }
 
 // 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);
@@ -142,7 +142,7 @@ static unsigned poly_gcd4(void)
 }
 
 // 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;
@@ -167,7 +167,7 @@ static unsigned poly_gcd5(void)
 }
 
 // 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;
@@ -187,7 +187,7 @@ static unsigned poly_gcd5p(void)
 }
 
 // Trivariate inputs with increasing degrees
-static unsigned poly_gcd6(void)
+static unsigned poly_gcd6()
 {
        symbol y("y");
 
@@ -205,7 +205,7 @@ static unsigned poly_gcd6(void)
 }
 
 // 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;
@@ -226,7 +226,7 @@ static unsigned poly_gcd7(void)
        return 0;
 }
 
-unsigned exam_polygcd(void)
+unsigned exam_polygcd()
 {
        unsigned result = 0;
        
index c6203df1d85aa9cad152bfff2d64a0852763eaee..be62bfcf511df6cf58e06acd948388b8eb920e35 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "exams.h"
 
-static unsigned exam_powerlaws1(void)
+static unsigned exam_powerlaws1()
 {
        // (x^a)^b = x^(a*b)
        
@@ -100,7 +100,7 @@ static unsigned exam_powerlaws1(void)
        return 0;
 }
 
-static unsigned exam_powerlaws2(void)
+static unsigned exam_powerlaws2()
 {
        // (a*x)^b = a^b * x^b
        
@@ -198,7 +198,7 @@ static unsigned exam_powerlaws2(void)
        return 0;
 }
 
-static unsigned exam_powerlaws3(void)
+static unsigned exam_powerlaws3()
 {
        // numeric evaluation
 
@@ -237,7 +237,7 @@ static unsigned exam_powerlaws3(void)
        return 0;
 }
 
-static unsigned exam_powerlaws4(void)
+static unsigned exam_powerlaws4()
 {
        // test for mul::eval()
        
@@ -262,7 +262,7 @@ static unsigned exam_powerlaws4(void)
        return 0;
 }
 
-static unsigned exam_powerlaws5(void)
+static unsigned exam_powerlaws5()
 {
        // cabinet of slightly pathological cases
        
@@ -284,7 +284,7 @@ static unsigned exam_powerlaws5(void)
        return 0;
 }
 
-unsigned exam_powerlaws(void)
+unsigned exam_powerlaws()
 {
        unsigned result = 0;
        
index f757d5007ac8fa7e42329462af5f9cf923d121a2..ab1ca0f6a72c6eb2c4e012f846d8a5c59bbfc041 100644 (file)
@@ -32,14 +32,14 @@ static unsigned check_series(const ex &e, const ex &point, const ex &d, int orde
                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;
@@ -107,7 +107,7 @@ static unsigned exam_series1(void)
 }
 
 // Series addition
-static unsigned exam_series2(void)
+static unsigned exam_series2()
 {
        unsigned result = 0;
        ex e, d;
@@ -120,7 +120,7 @@ static unsigned exam_series2(void)
 }
 
 // Series multiplication
-static unsigned exam_series3(void)
+static unsigned exam_series3()
 {
        unsigned result = 0;
        ex e, d;
@@ -133,7 +133,7 @@ static unsigned exam_series3(void)
 }
 
 // Series exponentiation
-static unsigned exam_series4(void)
+static unsigned exam_series4()
 {
        unsigned result = 0;
        ex e, d;
@@ -150,7 +150,7 @@ static unsigned exam_series4(void)
 }
 
 // Order term handling
-static unsigned exam_series5(void)
+static unsigned exam_series5()
 {
        unsigned result = 0;
        ex e, d;
@@ -170,7 +170,7 @@ static unsigned exam_series5(void)
 }
 
 // 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) +
@@ -202,7 +202,7 @@ static unsigned exam_series6(void)
 }
        
 // 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
@@ -212,7 +212,7 @@ static unsigned exam_series7(void)
 }
 
 // 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
@@ -221,7 +221,7 @@ static unsigned exam_series8(void)
 }
 
 // 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
@@ -231,7 +231,7 @@ static unsigned exam_series9(void)
 }
 
 // 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)
@@ -243,7 +243,7 @@ static unsigned exam_series10(void)
 }
 
 // Series expansion of logarithms around branch points
-static unsigned exam_series11(void)
+static unsigned exam_series11()
 {
        unsigned result = 0;
        ex e, d;
@@ -283,7 +283,7 @@ static unsigned exam_series11(void)
 }
 
 // Series expansion of other functions around branch points
-static unsigned exam_series12(void)
+static unsigned exam_series12()
 {
        unsigned result = 0;
        ex e, d;
@@ -309,7 +309,7 @@ static unsigned exam_series12(void)
 }
 
 
-unsigned exam_pseries(void)
+unsigned exam_pseries()
 {
        unsigned result = 0;
        
index 09870db838d8d2bb2c3a61d7f035bf0e85b64ef8..e88bd735cf4a54223bb528bc626a3856a6fc81c1 100644 (file)
@@ -84,8 +84,8 @@ public:
        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); }
@@ -100,8 +100,8 @@ protected:
 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:
 };
@@ -132,8 +132,8 @@ const ex Sigma::evaluate(const symbol &x, const unsigned grad) const
 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:
 };
@@ -145,8 +145,8 @@ 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:
 };
@@ -179,7 +179,7 @@ const ex Gamma::evaluate(const symbol &x, const unsigned grad) const
 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:
@@ -218,7 +218,7 @@ public:
        ~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:
@@ -274,7 +274,7 @@ const ex node::evaluate(const symbol &x, unsigned grad) const
        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) {
@@ -473,7 +473,7 @@ static unsigned test_tree(const node (*tree_generator)(unsigned=0))
        return 0;
 }
 
-unsigned time_antipode(void)
+unsigned time_antipode()
 {
        unsigned result = 0;
        timer jaeger_le_coultre;
index ea3b7be5abe9b812175a596ee8fbfccc16b23b77..66531bdcb2170e3dd8349b75ef36041a35bf64b9 100644 (file)
@@ -53,7 +53,7 @@ static unsigned expand_subs(unsigned size)
        return result;
 }
 
-unsigned time_dennyfliegner(void)
+unsigned time_dennyfliegner()
 {
        unsigned result = 0;
        
index 97f5bcd9d6a83b18e692d532d8574796184f4434..274d098f9421a9d5a12aa51f78ac3b73d86aa9d0 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        unsigned result = 0;
        const symbol x("x"), y("y"), z("z");
@@ -42,7 +42,7 @@ static unsigned test(void)
        return result;
 }
 
-unsigned time_fateman_expand(void)
+unsigned time_fateman_expand()
 {
        unsigned result = 0;
        unsigned count = 0;
index 96eb85faa2f39aef789c0364db8ad70a0361c3c9..afb78395163f4efab5bd8f8288e2ea746dc2eaca 100644 (file)
@@ -43,7 +43,7 @@ unsigned tgammaseries(unsigned order)
        return result;
 }
 
-unsigned time_gammaseries(void)
+unsigned time_gammaseries()
 {
        unsigned result = 0;
 
index 6badd19a2ac29515644800090cdee5bc7fbe94f9..67fcf62c84425b94cc9d29696bbb64a2d372207b 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        for (int i=1; i<=99; ++i)
                factorial(1000+i)/factorial(900+i);
@@ -36,7 +36,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_A(void)
+unsigned time_lw_A()
 {
        unsigned result = 0;
        unsigned count = 0;
index cb92efcc7a2096c8565b064532f8a61a349b7255..a2794dc64fe911640bbad7e55221c57ce88fa040 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        numeric s;
        
@@ -37,7 +37,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_B(void)
+unsigned time_lw_B()
 {
        unsigned result = 0;
        unsigned count = 0;
index 70960ad91bcf7d7468c6d093eeb8e60ef2987c75..2f61a05e54b9046deb8768bae03fe7059bf688c7 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        numeric x(13*17*31);
        numeric y(13*19*29);
@@ -41,7 +41,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_C(void)
+unsigned time_lw_C()
 {
        unsigned result = 0;
        unsigned count = 0;
index 631b1cb757a444c1c2f3fb8afaa77c3ec8394772..2bf36949cf592f05495018310cd81e5d040a536a 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        ex s;
        symbol y("y");
@@ -41,7 +41,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_D(void)
+unsigned time_lw_D()
 {
        unsigned result = 0;
        unsigned count = 0;
index 59c590fbb3183bdf584e3a0fe8b164b943dee876..4a2abcee0098abc0f7892f9c081983d816608293 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        ex s;
        symbol y("y");
@@ -41,7 +41,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_E(void)
+unsigned time_lw_E()
 {
        unsigned result = 0;
        unsigned count = 0;
index 912a0cd294cc185ac9cfa2dbf7c27cc143f8160d..bfd8dcb614029182d48ef24028afb19c94849577 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        symbol x("x");
        symbol y("y");
@@ -38,7 +38,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_F(void)
+unsigned time_lw_F()
 {
        unsigned result = 0;
        unsigned count = 0;
index 43b0c6e20e0645d940ec5d01dcbd6bbb2b402087..b65af06651ce4fe35c52a62c7f03b0b26fa79990 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        symbol x("x");
        symbol y("y");
@@ -41,7 +41,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_G(void)
+unsigned time_lw_G()
 {
        unsigned result = 0;
        unsigned count = 0;
index a36e5f249f1fce0a629f885b2e7fd248c0811f46..e988e46b652d90a3f3a14f076a4176489776e9fe 100644 (file)
@@ -56,7 +56,7 @@ static unsigned test(unsigned n)
        return 0;
 }
 
-unsigned time_lw_H(void)
+unsigned time_lw_H()
 {
        unsigned result = 0;
        unsigned count = 0;
index 18a42d8baee08fb2b592bb004b3aeca4788474ea..cc8641773d08bc7a96a9f8227315f928115d030c 100644 (file)
@@ -79,7 +79,7 @@ static unsigned test(unsigned n)
        return result;
 }
 
-unsigned time_lw_IJKL(void)
+unsigned time_lw_IJKL()
 {
        unsigned result = 0;
        
index cfba9fce8219573c8964f4f71078bad706fa2623..54494c8e9741f29ebc565f7dbcb8f5c34ae6d950 100644 (file)
@@ -23,7 +23,7 @@
 
 #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");
@@ -73,7 +73,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_M1(void)
+unsigned time_lw_M1()
 {
        unsigned result = 0;
        unsigned count = 0;
index 9b35c9f28d0525030044a34489c3081514439440..b835f602f1b08a13567411ccdc79c731f9f7b9c7 100644 (file)
@@ -25,7 +25,7 @@
 
 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");
@@ -149,7 +149,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_M2(void)
+unsigned time_lw_M2()
 {
        unsigned result = 0;
        unsigned count = 0;
index 81d32b0496ddc52c1f9c9ef663331a6f7b46c3ae..f55d56bb6eea776e77ff95b146ca8332e2fb2e90 100644 (file)
@@ -26,7 +26,7 @@
 
 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");
@@ -52,7 +52,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_N(void)
+unsigned time_lw_N()
 {
        unsigned result = 0;
        unsigned count = 0;
index 1199043ecde4b295ce317b7cf26faf76036698f8..f24016d524104ff13108da5c250fdac36433b6c3 100644 (file)
@@ -25,7 +25,7 @@
 
 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");
@@ -100,7 +100,7 @@ static unsigned test1(void)
        return 0;
 }
 
-unsigned time_lw_O(void)
+unsigned time_lw_O()
 {
        unsigned result = 0;
        unsigned count = 0;
index a523e8980a0b7734980d623e0e0bd190a91bde1c..279327be1c6ae12db7cdd5b56bec3868de385299 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        // This is a pattern that comes up in graph theory:
        const unsigned n = 10;
@@ -51,7 +51,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_P(void)
+unsigned time_lw_P()
 {
        unsigned result = 0;
        unsigned count = 0;
index 99d78692bda2421cb902061c39f027d5ce9ec211..69e07800dc26bc465bdf8d1539c0d3bb6a1ec079 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "times.h"
 
-static unsigned test(void)
+static unsigned test()
 {
        // create the matrix from test P...
        const unsigned n = 10;
@@ -64,7 +64,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_Pprime(void)
+unsigned time_lw_Pprime()
 {
        unsigned result = 0;
        unsigned count = 0;
index b48a30cf1211e9dcc4ada1e6c4515cb5e867ab8d..8c976a1f9aa3831b53f53f7b51550305bfc0222a 100644 (file)
@@ -23,9 +23,9 @@
 
 #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;
@@ -54,7 +54,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_Q(void)
+unsigned time_lw_Q()
 {
        unsigned result = 0;
        unsigned count = 0;
index 46dac14a9ae9b8c23f511135413841c6779f9ea5..b69cb91eca5590af79fc367137b51ce939a1b6e4 100644 (file)
@@ -23,9 +23,9 @@
 
 #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;
@@ -66,7 +66,7 @@ static unsigned test(void)
        return 0;
 }
 
-unsigned time_lw_Qprime(void)
+unsigned time_lw_Qprime()
 {
        unsigned result = 0;
        unsigned count = 0;
index 573f00f943805ac76bcf0067c5c4f68df206785d..693b8f77573dfd12983c894778ce2b64bccd6511 100644 (file)
@@ -63,7 +63,7 @@ static unsigned toeplitz_det(unsigned size)
        return result;
 }
 
-unsigned time_toeplitz(void)
+unsigned time_toeplitz()
 {
        unsigned result = 0;
 
index 4b4c965af70980df8eb2002715b1dfaac97590d2..17fa65bacc541acfe774745065858f5d1f78d129 100644 (file)
@@ -61,7 +61,7 @@ static unsigned vandermonde_det(unsigned size)
        return result;
 }
 
-unsigned time_vandermonde(void)
+unsigned time_vandermonde()
 {
        unsigned result = 0;
        
index fe0d16018cc6eda9bcbc1c9489450c86dace5333..2a11872de77501d062d50501833972fa42b1f2b5 100644 (file)
  *  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())
@@ -60,7 +64,7 @@ double timer::read(void)
        return 0.01*int(elapsed*100+0.5);
 }
 
-bool timer::running(void)
+bool timer::running()
 {
        return on;
 }
diff --git a/check/timer.h b/check/timer.h
new file mode 100644 (file)
index 0000000..022c29d
--- /dev/null
@@ -0,0 +1,41 @@
+/** @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
index 5d53b9f3858bcee7abb0f3ddd1f3e854f2587b27..85052de0bb56427dbe1c3ce06e3d1d920aba0084 100644 (file)
@@ -23,7 +23,6 @@
 #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();
index dd4eadecbcd80643616fcd7b05fcb35de56a23bb..af1b549644843c2c73217f8e71aee908ae18107b 100644 (file)
@@ -19,10 +19,10 @@ dnl autoconf sees "AC_MAJOR_VERSION" and complains about an undefined macro
 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)
@@ -115,6 +115,7 @@ AC_CHECK_HEADER(sstream, , GINAC_ERROR([The standard <sstream> header file could
 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,
index 190fcdb72107c85effdda54b7a5b2556810c173c..7ad4568e76abc66ffb4e615321443e74b88b51f2 100644 (file)
@@ -1,32 +1,15 @@
-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
 
index 97f3b101a3151cca5600b2e1cd763dfb46d990f4..08df8712627e6993d5aecb7b9f3b30b62c5367c5 100644 (file)
@@ -2,10 +2,10 @@ Source: ginac
 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}
@@ -16,12 +16,12 @@ Description: The GiNaC framework (runtime library)
  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)
@@ -30,8 +30,7 @@ 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
@@ -44,4 +43,4 @@ Description: Some tools for the GiNaC framework
  .
  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.
index 7cb8b5e35ecbe6082722897c03e068551651a9e0..b10400460eaefd1797c8184978d26b68dc262b09 100644 (file)
@@ -1,4 +1,4 @@
-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/>
diff --git a/debian/docs b/debian/docs
new file mode 100644 (file)
index 0000000..eb9b151
--- /dev/null
@@ -0,0 +1,3 @@
+NEWS
+README
+AUTHORS
index 7f1990964414e16a5726643627b03152c4da6f28..c57db5d944e56f75c83d01037e6e39e613f324b4 100644 (file)
@@ -1,5 +1,8 @@
 #!/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#
similarity index 100%
rename from debian/dirs
rename to debian/libginac1.1.dirs
diff --git a/debian/libginac1.1.files b/debian/libginac1.1.files
new file mode 100644 (file)
index 0000000..9a5c1be
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/libginac*.so.*
diff --git a/debian/postinst b/debian/postinst
deleted file mode 100644 (file)
index 1ded2f8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-set -e
-if [ "$1" = "configure" ]; then
-  ldconfig
-fi
-#DEBHELPER#
index b3856a320e46f5be2978c6150e2a40bf54b5195c..a6d80b1937391037d2704a659c36c62c91522f25 100755 (executable)
@@ -1,53 +1,85 @@
 #!/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 
index 6a0cdd01ffbce4abeea6998395291fb8e0aa33bd..ce7d3dcbc27dc85272f5f077cf9ea35a5ad41b0e 100644 (file)
@@ -1 +1 @@
-libginac-1.0   0       libginac0 (>= 1.0.0)
+libginac-1.1   0       libginac1.1 (>= 1.1.0)
index 868b75361d9590423fc991e32ff56478f41e8ffa..0f5c484333a8b2729234f500dc80d661c739d9eb 100644 (file)
@@ -1,6 +1,7 @@
-# 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:
@@ -14,7 +15,7 @@
 #---------------------------------------------------------------------------
 
 # 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
 
@@ -29,73 +30,94 @@ PROJECT_NUMBER         =
 # 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
 
@@ -109,29 +131,13 @@ STRIP_FROM_PATH        =
 # 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
 
@@ -143,21 +149,27 @@ 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
 
@@ -165,25 +177,40 @@ 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
 
@@ -195,15 +222,10 @@ 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.
@@ -216,63 +238,92 @@ GENERATE_TODOLIST      = NO
 
 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           = 
 
@@ -283,51 +334,65 @@ 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             = 
 
@@ -336,36 +401,62 @@ 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          = 
 
@@ -374,16 +465,22 @@ 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.
@@ -399,39 +496,72 @@ HTML_FOOTER            = Doxyfooter
 # 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
 
@@ -446,57 +576,67 @@ TREEVIEW_WIDTH         = 250
 #---------------------------------------------------------------------------
 
 # 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
 
@@ -512,97 +652,146 @@ GENERATE_RTF           = 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)="
@@ -610,31 +799,45 @@ PREDEFINED             = "GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(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
 
@@ -642,10 +845,24 @@ 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
 
@@ -659,38 +876,56 @@ CLASS_GRAPH            = YES
 # 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
 
@@ -698,56 +933,62 @@ 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          = 
index dd854fdfe762a23baec2d362fc32ee53107a13f7..2c0e87913336914bccd12ed44ef942a47d89206e 100644 (file)
@@ -1,6 +1,7 @@
-# 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:
@@ -14,7 +15,7 @@
 #---------------------------------------------------------------------------
 
 # 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
 
@@ -29,73 +30,94 @@ PROJECT_NUMBER         =
 # 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
 
@@ -109,29 +131,13 @@ STRIP_FROM_PATH        =
 # 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
 
@@ -143,21 +149,27 @@ 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
 
@@ -165,25 +177,40 @@ 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
 
@@ -195,15 +222,10 @@ 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.
@@ -216,63 +238,92 @@ GENERATE_TODOLIST      = NO
 
 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           = 
 
@@ -283,51 +334,65 @@ 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             = 
 
@@ -336,36 +401,62 @@ 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          = 
 
@@ -374,16 +465,22 @@ 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.
@@ -399,39 +496,72 @@ HTML_FOOTER            = Doxyfooter
 # 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
 
@@ -446,57 +576,67 @@ TREEVIEW_WIDTH         = 250
 #---------------------------------------------------------------------------
 
 # 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
 
@@ -512,97 +652,146 @@ GENERATE_RTF           = 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)="
@@ -610,31 +799,45 @@ PREDEFINED             = "GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(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
 
@@ -642,10 +845,24 @@ 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
 
@@ -659,38 +876,56 @@ CLASS_GRAPH            = YES
 # 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
 
@@ -698,56 +933,62 @@ 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          = 
index 79eb9708861e60f53d4e93b969bd6ab8ca8f1e82..406948071a2c2ac854d3b70f146de8629f07c58f 100644 (file)
@@ -48,7 +48,7 @@ reference.ps: latex latex/reference.ps
 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:
@@ -61,7 +61,7 @@ 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
@@ -69,4 +69,4 @@ install-data-local:
 uninstall-local:
        rm -f $(DESTDIR)$(ginacreferencedir)/doxygen.css
        rm -f $(DESTDIR)$(ginacreferencedir)/*.html
-       rm -f $(DESTDIR)$(ginacreferencedir)/*.gif
+       rm -f $(DESTDIR)$(ginacreferencedir)/*.png
index 517426736a3bd098e5f3f382da844e1d2f41484f..241d254109746d91983ef82efaa3b72ba15afb24 100644 (file)
@@ -808,7 +808,7 @@ at a singularity.
 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
@@ -831,7 +831,7 @@ exceptions generated by GiNaC:
 using namespace std;
 using namespace GiNaC;
 
-int main(void)
+int main()
 @{
     try @{
         ...
@@ -1274,6 +1274,7 @@ and safe simplifications are carried out like transforming
 @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
@@ -1303,11 +1304,60 @@ individual elements:
     ...
 @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
@@ -1332,6 +1382,14 @@ and @code{remove_last()}:
     ...
 @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
@@ -1515,9 +1573,8 @@ Here are a couple of examples of constructing matrices:
 @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;
@@ -1525,8 +1582,7 @@ matrix matrix::sub(const matrix & other) const;
 matrix matrix::mul(const matrix & other) const;
 matrix matrix::mul_scalar(const ex & other) const;
 matrix matrix::pow(const ex & expn) const;
-matrix matrix::transpose(void) const;
-matrix matrix::inverse(void) const;
+matrix matrix::transpose() const;
 @end example
 
 All of these methods return the result as a new matrix object. Here is an
@@ -1604,16 +1660,36 @@ computing determinants, traces, and characteristic polynomials:
 @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
@@ -1678,6 +1754,9 @@ int main()
     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
 
@@ -1690,6 +1769,10 @@ construct an expression containing one indexed object, @samp{A.i.j}. It has
 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
@@ -1738,8 +1821,8 @@ anything useful with it.
 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
@@ -1750,10 +1833,10 @@ object, you can get a reference to the @code{idx} object with the function
 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
@@ -1784,8 +1867,8 @@ this can be overridden by supplying a third argument to the @code{varidx}
 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>()}
@@ -1793,7 +1876,7 @@ to get the object reference from an expression). There's also the very useful
 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
@@ -1827,8 +1910,8 @@ supplying a fourth argument to the @code{spinidx} constructor. The two
 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
@@ -1836,8 +1919,8 @@ 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
@@ -1997,7 +2080,7 @@ indices into a canonical order which allows for some immediate simplifications:
 @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
@@ -2058,7 +2141,7 @@ and calculating traces and convolutions of matrices and predefined tensors)
 there is the method
 
 @example
-ex ex::simplify_indexed(void);
+ex ex::simplify_indexed();
 ex ex::simplify_indexed(const scalar_products & sp);
 @end example
 
@@ -2408,8 +2491,8 @@ Information about the commutativity of an object or expression can be
 obtained with the two member functions
 
 @example
-unsigned ex::return_type(void) const;
-unsigned ex::return_type_tinfo(void) const;
+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
@@ -2795,12 +2878,14 @@ avoided.
 * 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
 
@@ -2826,8 +2911,8 @@ GiNaC provides a couple of functions for this:
 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
@@ -2955,8 +3040,8 @@ for an explanation of these.
 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
@@ -3286,9 +3371,9 @@ bool ex::find(const ex & pattern, lst & found);
 @end example
 
 works a bit like @code{has()} but it doesn't stop upon finding the first
-match. Instead, it 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
@@ -3348,11 +3433,63 @@ The last example would be written in C++ in this way:
 @}
 @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
@@ -3369,7 +3506,7 @@ ex calc_trace(ex e)
         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)) @{
@@ -3494,7 +3631,214 @@ argument. You can not use functions like @samp{diff()}, @samp{op()},
 @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
 
@@ -3592,34 +3936,9 @@ int ex::degree(const ex & s);
 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);
@@ -3890,7 +4209,8 @@ If you need both numerator and denominator, calling @code{numer_denom()} is
 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
@@ -3898,6 +4218,10 @@ functions. GiNaC provides a way to extend the domain of these functions to
 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
@@ -3906,10 +4230,33 @@ on the expression to be converted. The supplied @code{lst} will be filled
 with the generated temporary symbols and their replacement expressions in
 a format that can be used directly for the @code{subs()} method. It can also
 already contain a list of replacements from an earlier application of
-@code{.to_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
 @{
@@ -3918,13 +4265,11 @@ For 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
@@ -4042,19 +4387,21 @@ value of Archimedes' constant
 $\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>
@@ -4150,7 +4497,7 @@ almost any kind of object (anything that is @code{subs()}able):
 @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
 
@@ -4264,7 +4611,48 @@ standard incorporate these functions in the complex domain in a manner
 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
@@ -4273,70 +4661,99 @@ compatible with C99.
 @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
 
@@ -4344,41 +4761,63 @@ produces
 
 @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
@@ -4392,9 +4831,9 @@ static void my_print(const ex & e)
     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 << ",";
@@ -4404,7 +4843,7 @@ static void my_print(const ex & e)
     cout << ")";
 @}
 
-int main(void)
+int main()
 @{
     my_print(pow(3, x) - 2 * sin(y / Pi)); cout << endl;
     return 0;
@@ -4435,22 +4874,19 @@ and have the @samp{x} and @samp{y} correspond to the symbols @code{x} and
 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:
 
@@ -4582,8 +5018,8 @@ static void my_print2(const archive_node & n)
     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;
@@ -4634,7 +5070,7 @@ static void my_print2(const archive_node & n)
     cout << ")";
 @}
 
-int main(void)
+int main()
 @{
     ex e = pow(2, x) - y;
     archive ar(e, "e");
@@ -4669,7 +5105,8 @@ authors---they will happily incorporate them into future versions.
 @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
 
 
@@ -4697,7 +5134,7 @@ inefficient.  For this purpose, the underlying foundation classes
 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
 
@@ -4963,21 +5400,375 @@ specifications. GiNaC will automatically rearrange the arguments of
 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
 
@@ -5080,14 +5871,13 @@ the first line after the opening brace of the class definition. The
 source (at global scope, of course, not inside a function).
 
 @code{GINAC_DECLARE_REGISTERED_CLASS} contains, among other things the
-declarations of the default 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
@@ -5095,33 +5885,23 @@ class:
 @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}
@@ -5143,10 +5923,7 @@ which are the two constructors we declared.
 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
@@ -5154,51 +5931,13 @@ 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
@@ -5223,7 +5962,7 @@ The unarchiving constructor is basically the inverse of the archiving
 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);
 @}
@@ -5237,7 +5976,7 @@ by the unarchiving constructor of the @code{basic} class.
 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);
 @}
@@ -5278,15 +6017,8 @@ all relevant member variables.
 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
@@ -5435,11 +6167,35 @@ cout << e << endl;
  // -> 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;
@@ -5448,33 +6204,21 @@ ex series(const relational & r, int order, unsigned options = 0) 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
@@ -5650,12 +6394,19 @@ any other programming language.
 @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>
@@ -5982,7 +6733,7 @@ and the @samp{AM_PATH_GINAC} macro. The program used here is @file{simple.cpp}:
 @example
 #include <ginac/ginac.h>
 
-int main(void)
+int main()
 @{
     GiNaC::symbol x("x");
     GiNaC::ex a = GiNaC::sin(x);
@@ -6089,7 +6840,7 @@ and George Labahn, ISBN 0-7923-9259-0, 1992, Kluwer Academic Publishers, Norwell
 
 @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
@@ -6100,6 +6851,10 @@ Michael J. Wester (editor), ISBN 0-471-98353-5, 1999, Wiley, Chichester
 @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
 
index 496cb4469eabeed63329da31e12dcfe07c135774..36c3d8b021f9a63f31cb149f3427fd59290e2fcc 100644 (file)
--- a/ginac.m4
+++ b/ginac.m4
@@ -91,7 +91,7 @@ dnl match the version of the headers and the version built into the library, too
    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;
index f0896bd4d802447fd52bfc63ca53000829c75eef..2b961fc1ff755fa8c8a74bcb498ed82060bb5277 100644 (file)
@@ -1,36 +1,31 @@
 ## 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
index 9edbf13947304b8f26756e06f3119522ccd926c1..511f3b3d23da1cb12ced5edc485b17175e660ee6 100644 (file)
@@ -25,8 +25,9 @@
 
 #include "add.h"
 #include "mul.h"
-#include "matrix.h"
 #include "archive.h"
+#include "operators.h"
+#include "matrix.h"
 #include "utils.h"
 
 namespace GiNaC {
@@ -34,7 +35,7 @@ namespace GiNaC {
 GINAC_IMPLEMENT_REGISTERED_CLASS(add, expairseq)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
 add::add()
@@ -42,9 +43,6 @@ add::add()
        tinfo_key = TINFO_add;
 }
 
-DEFAULT_COPY(add)
-DEFAULT_DESTROY(add)
-
 //////////
 // other constructors
 //////////
@@ -163,7 +161,7 @@ void add::print(const print_context & c, unsigned level) const
 
                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);
                }
@@ -331,7 +329,7 @@ ex add::eval(int level) const
        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;
@@ -357,7 +355,7 @@ ex add::eval(int level) const
        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.
@@ -372,7 +370,7 @@ ex add::evalm(void) const
        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;
@@ -390,12 +388,12 @@ ex add::evalm(void) const
                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
@@ -423,12 +421,7 @@ int add::compare_same_type(const basic & other) const
        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;
@@ -436,7 +429,7 @@ unsigned add::return_type(void) const
                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;
@@ -456,7 +449,7 @@ ex add::thisexpairseq(epvector * vp, const ex & oc) const
 
 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);
@@ -473,7 +466,7 @@ expair add::combine_ex_with_coeff_to_pair(const ex & e,
                                                                                  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);
@@ -481,14 +474,14 @@ expair add::combine_ex_with_coeff_to_pair(const ex & e,
                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);
        }
@@ -501,7 +494,7 @@ expair add::combine_pair_with_coeff_to_pair(const expair & p,
        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);
        }
index 4f55240ade432133c4cde263969714cb70a6bad5..f2a94ed416db167f881c8cd258b21621c2bdc80d 100644 (file)
@@ -46,25 +46,24 @@ public:
        // 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;
index 28d8afc3dbde5ca0daccfcf1ab0d0fcafd34049e..3b6e2931fc6231298738e1bcd2900d057a43fa45 100644 (file)
@@ -26,6 +26,7 @@
 #include "archive.h"
 #include "registrar.h"
 #include "ex.h"
+#include "lst.h"
 #include "config.h"
 #include "tostring.h"
 
@@ -49,18 +50,19 @@ void archive::archive_ex(const ex &e, const char *name)
  *  @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;
 }
 
 
@@ -89,7 +91,8 @@ ex archive::unarchive_ex(const lst &sym_lst, const char *name) const
 
 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
@@ -98,7 +101,8 @@ 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
@@ -110,10 +114,11 @@ ex archive::unarchive_ex(const lst &sym_lst, std::string &name, unsigned index)
        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();
 }
@@ -316,18 +321,11 @@ const std::string &archive::unatomize(archive_atom id) const
 }
 
 
-/** 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;
@@ -432,7 +430,7 @@ bool archive_node::find_string(const std::string &name, std::string &ret, unsign
        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();
@@ -493,7 +491,7 @@ void archive_node::get_properties(propinfovector &v) const
 
 
 /** 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)
@@ -512,45 +510,23 @@ ex archive_node::unarchive(const lst &sym_lst) const
 }
 
 
-/** 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;
@@ -624,7 +600,7 @@ void archive_node::printraw(std::ostream &os) const
 
 /** 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;
index b7e9ba989e296a55e907a547ac0dcb3193236801..5423dbfcd2aa9a0046b75d4e7d3d3978bfecdd34 100644 (file)
 #include <iosfwd>
 #include <string>
 #include <vector>
+#include <map>
 
 namespace GiNaC {
 
-class lst;
 class archive;
 
 
@@ -65,10 +65,6 @@ public:
        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. */
@@ -79,9 +75,7 @@ public:
        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. */
@@ -110,7 +104,7 @@ public:
 
        /** 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. */
@@ -119,23 +113,21 @@ public:
        /** 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. */
@@ -199,18 +191,18 @@ public:
        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:
@@ -236,6 +228,10 @@ public:
 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;
 };
 
 
index f625e92b342a39e3538fa397649d5fc836e7e237..9921d3581c80a73d978e06799fd903d01e16b6bb 100644 (file)
@@ -34,6 +34,7 @@
 #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;
@@ -109,13 +122,13 @@ void basic::archive(archive_node &n) const
  *               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
@@ -127,8 +140,9 @@ void basic::print(const print_context & c, unsigned level) const
  *  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;
@@ -136,27 +150,18 @@ void basic::dbgprint(void) const
 
 /** 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 */
@@ -167,7 +172,7 @@ bool basic::info(unsigned inf) const
 }
 
 /** 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
@@ -176,30 +181,44 @@ unsigned basic::nops() const
 }
 
 /** 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
@@ -209,7 +228,7 @@ bool basic::has(const ex & pattern) const
        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;
        
@@ -220,17 +239,16 @@ bool basic::has(const ex & pattern) const
  *  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. */
@@ -260,7 +278,7 @@ ex basic::coeff(const ex & s, int n) const
 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)
@@ -271,7 +289,7 @@ ex basic::collect(const ex & s, bool distributed) const
                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;
@@ -280,7 +298,7 @@ ex basic::collect(const ex & s, bool distributed) const
                        };
                        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);
@@ -291,14 +309,14 @@ ex basic::collect(const ex & s, bool distributed) const
 
                                // 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) {
@@ -308,7 +326,7 @@ ex basic::collect(const ex & s, bool distributed) const
                                                        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;
                                        }
@@ -325,8 +343,13 @@ done:              delete[] si;
 
                        // 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 {
@@ -344,7 +367,7 @@ done:               delete[] si;
 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(). */
@@ -377,7 +400,7 @@ struct evalm_map_function : public map_function {
 } map_evalm;
 
 /** Evaluate sums, products and integer powers of matrices. */
-ex basic::evalm(void) const
+ex basic::evalm() const
 {
        if (nops() == 0)
                return *this;
@@ -459,14 +482,14 @@ bool basic::match(const ex & pattern, lst & repl_lst) const
        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;
@@ -491,7 +514,7 @@ bool basic::match(const ex & pattern, lst & repl_lst) const
                        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;
 
@@ -500,28 +523,64 @@ bool basic::match(const ex & pattern, lst & repl_lst) const
        }
 }
 
-/** 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.
@@ -549,14 +608,14 @@ ex basic::diff(const symbol & s, unsigned nth) const
 }
 
 /** 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
@@ -619,12 +678,12 @@ bool basic::match_same_type(const basic & other) const
        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();
 }
@@ -635,17 +694,14 @@ unsigned basic::return_type_tinfo(void) const
  *  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);
@@ -686,77 +742,67 @@ ex basic::expand(unsigned options) const
  *  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.
@@ -779,18 +825,18 @@ bool basic::is_equal(const basic & other) const
 /** 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);
 }
 
 //////////
index d2d3e865840462c865ae0a0b3d474dc09e42b78a..a68c2eee0411dba6f5dca043789c55eef099bd18 100644 (file)
@@ -23,6 +23,7 @@
 #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;
 
@@ -53,6 +55,15 @@ struct map_function {
 };
 
 
+/** 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
@@ -60,88 +71,133 @@ 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;}
@@ -150,7 +206,7 @@ public:
        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:
@@ -158,29 +214,31 @@ 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. */
index b6dd31ef9d09e7765ba36fec1be0c5b0fd7c1a6c..547285d0f3355f693bd0f2aafb5f9d33decca998 100644 (file)
@@ -32,6 +32,7 @@
 #include "symmetry.h"
 #include "lst.h"
 #include "relational.h"
+#include "operators.h"
 #include "mul.h"
 #include "print.h"
 #include "archive.h"
@@ -47,7 +48,7 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(diracgammaL, tensor)
 GINAC_IMPLEMENT_REGISTERED_CLASS(diracgammaR, tensor)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructors
 //////////
 
 clifford::clifford() : representation_label(0)
@@ -55,18 +56,11 @@ 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
@@ -103,7 +97,7 @@ clifford::clifford(unsigned char rl, exvector * vp) : inherited(sy_none(), vp),
 // 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);
@@ -295,7 +289,7 @@ bool diracgamma::contract_with(exvector::iterator self, exvector::iterator other
 /** 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());
@@ -453,17 +447,17 @@ ex clifford::simplify_ncmul(const exvector & v) const
        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);
 }
@@ -500,16 +494,6 @@ ex dirac_gammaR(unsigned char rl)
        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
@@ -534,13 +518,13 @@ static bool is_clifford_tinfo(unsigned ti)
 
 /** 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])
@@ -556,8 +540,8 @@ static ex trace_string(exvector::const_iterator ix, unsigned num)
        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];
@@ -582,11 +566,11 @@ ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE)
                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);
@@ -595,7 +579,7 @@ ex dirac_trace(const ex & e, unsigned char rl, const ex & 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;
@@ -610,7 +594,7 @@ ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE)
 
                // 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) {
 
@@ -634,23 +618,23 @@ ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE)
                        //   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;
@@ -681,7 +665,7 @@ ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE)
                        }
 
                        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();
@@ -702,19 +686,20 @@ ex canonicalize_clifford(const ex & e)
        // 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)))
@@ -722,7 +707,7 @@ ex canonicalize_clifford(const ex & e)
 
                        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
@@ -741,7 +726,7 @@ ex canonicalize_clifford(const ex & e)
                                        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;
index ce5d2acfd50a6b3430d5717c9aa125389d19f3fc..8dbc3767ddb94330fee5530ab7a90f7a0fb52489 100644 (file)
@@ -52,16 +52,16 @@ public:
        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:
@@ -167,10 +167,6 @@ ex dirac_gammaL(unsigned char rl = 0);
  *  @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
index 4c50a6e7dd8f8c2b2abcab33eb927e2e869cbd78..fc66b544e5ee7ae775c8a28884a2e0e29b9b022a 100644 (file)
@@ -27,6 +27,7 @@
 #include "idx.h"
 #include "ncmul.h"
 #include "symmetry.h"
+#include "operators.h"
 #include "numeric.h"
 #include "mul.h"
 #include "power.h" // for sqrt()
@@ -44,7 +45,7 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(su3f, tensor)
 GINAC_IMPLEMENT_REGISTERED_CLASS(su3d, tensor)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructors
 //////////
 
 color::color() : representation_label(0)
@@ -52,17 +53,10 @@ 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
@@ -98,7 +92,7 @@ color::color(unsigned char rl, exvector * vp) : inherited(sy_none(), vp), repres
 // 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);
@@ -154,7 +148,7 @@ DEFAULT_PRINT(su3d, "d")
 
 /** 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());
@@ -162,7 +156,7 @@ ex color::simplify_ncmul(const exvector & v) const
        // 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++;
        }
@@ -170,15 +164,15 @@ ex color::simplify_ncmul(const exvector & v) const
        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);
 }
@@ -306,7 +300,7 @@ bool su3t::contract_with(exvector::iterator self, exvector::iterator other, exve
        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));
@@ -321,7 +315,7 @@ bool su3t::contract_with(exvector::iterator self, exvector::iterator other, exve
 
                // 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;
@@ -330,7 +324,7 @@ bool su3t::contract_with(exvector::iterator self, exvector::iterator other, exve
                } else {
                        exvector::iterator it = self + 1;
                        while (it != other) {
-                               if (!is_ex_of_type(*it, color)) {
+                               if (!is_a<color>(*it)) {
                                        return false;
                                }
                                it++;
@@ -360,7 +354,7 @@ bool su3d::contract_with(exvector::iterator self, exvector::iterator other, exve
        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();
@@ -388,11 +382,11 @@ bool su3d::contract_with(exvector::iterator self, exvector::iterator other, exve
                        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();
@@ -419,7 +413,7 @@ bool su3f::contract_with(exvector::iterator self, exvector::iterator other, exve
        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;
@@ -441,11 +435,11 @@ bool su3f::contract_with(exvector::iterator self, exvector::iterator other, exve
                        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();
@@ -475,7 +469,7 @@ ex color_ONE(unsigned char rl)
 
 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"));
@@ -485,7 +479,7 @@ ex color_T(const ex & a, unsigned char rl)
 
 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"));
@@ -495,7 +489,7 @@ ex color_f(const ex & a, const ex & b, const ex & c)
 
 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"));
@@ -517,19 +511,19 @@ static bool is_color_tinfo(unsigned ti, unsigned char rl)
 
 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);
@@ -538,17 +532,17 @@ ex color_trace(const ex & e, unsigned char 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) {
 
@@ -572,7 +566,7 @@ ex color_trace(const ex & e, unsigned char rl)
 
                        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;
index 66cf0769fde054fb041c72da024bd21b29157a8f..e7ad06184574d55ac9d79906fa5b1300ceb40666 100644 (file)
@@ -51,16 +51,16 @@ public:
 
        // 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:
index 636eeae4104eb7ad3b82377ac0de0d5729d038f4..d3c91588c186be4bfe64354fb553cdc4fd3bb405 100644 (file)
@@ -36,44 +36,24 @@ namespace GiNaC {
 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 + "}";
@@ -83,7 +63,7 @@ constant::constant(const std::string & initname, evalffunctype efun, const std::
 }
 
 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 + "}";
@@ -96,9 +76,9 @@ constant::constant(const std::string & initname, const numeric & initnumber, con
 // 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)
@@ -149,8 +129,8 @@ ex constant::evalf(int level) const
 {
        if (ef!=0) {
                return ef();
-       } else if (number != 0) {
-               return number->evalf();
+       } else {
+               return number.evalf();
        }
        return *this;
 }
@@ -184,14 +164,12 @@ bool constant::is_equal_same_type(const basic & other) const
        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;
 }
 
index e0242d970d060b98df09fbe63ca96a49cf31bfe5..0092ac3b1c9d308082cded8c523d72966a3da818 100644 (file)
@@ -29,7 +29,7 @@
 
 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
@@ -41,7 +41,7 @@ class constant : public basic
        
 // 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());
@@ -53,7 +53,7 @@ public:
 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
@@ -67,7 +67,7 @@ private:
        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;
 };
diff --git a/ginac/container.h b/ginac/container.h
new file mode 100644 (file)
index 0000000..135adb9
--- /dev/null
@@ -0,0 +1,626 @@
+/** @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__
diff --git a/ginac/container.pl b/ginac/container.pl
deleted file mode 100755 (executable)
index 9b02154..0000000
+++ /dev/null
@@ -1,685 +0,0 @@
-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";
index c69b30b08b92128a3287cbfd9961acb7e1fe4159..43b93766b9f0d2307c07f97583f4114d10de2412 100644 (file)
@@ -37,7 +37,7 @@
 namespace GiNaC {
 
 //////////
-// other ctors
+// other constructors
 //////////
 
 // none (all inlined)
@@ -55,34 +55,23 @@ namespace GiNaC {
  *  @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
@@ -96,8 +85,6 @@ ex ex::expand(unsigned options) const
  *  @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
@@ -124,46 +111,65 @@ bool ex::find(const ex & pattern, lst & found) const
                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
@@ -172,419 +178,285 @@ ex ex::rhs(void) const
  *  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;
 }
        
 //////////
index 14cfd5b54eb1f1ae8b6c3561bdd81a6520954ff2..eaa6b808c915b2433430f85974223bd1f68129af 100644 (file)
 #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
@@ -49,15 +50,7 @@ private:
 /** 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;
 
 
@@ -73,15 +66,15 @@ class ex
        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);
@@ -101,90 +94,125 @@ public:
        /** 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 &
@@ -194,25 +222,21 @@ public:
                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
@@ -221,115 +245,96 @@ public:
 
 // 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
@@ -338,9 +343,7 @@ ex::ex(const std::string &s, const ex &l)
 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);
 }
@@ -348,9 +351,7 @@ int ex::compare(const ex & other) const
 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);
 }
@@ -368,7 +369,7 @@ inline bool are_ex_trivially_equal(const ex &e1, const ex &e2)
 }
 
 // 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)
@@ -404,6 +405,9 @@ inline ex normal(const ex & thisex, int level=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); }
 
@@ -425,11 +429,11 @@ inline ex series(const ex & thisex, const ex & r, int order, unsigned options =
 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(); }
@@ -455,7 +459,7 @@ inline ex symmetrize_cyclic(const ex & thisex)
 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)
@@ -470,6 +474,7 @@ inline bool is_zero(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); }
index a170ae8649ba994b621ebc6ef15d51bde99c528f..2610e8fa47e3e0ec3e4fa3525aeb46f6cf54084f 100644 (file)
@@ -38,20 +38,7 @@ class expair
 {
 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)
        {
@@ -85,7 +72,7 @@ public:
        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)));
index 9f7116a63c18be26a7a6af024fc275bdc604d633..f8675b76e2a3e95ccc12901da790604888fee037 100644 (file)
@@ -33,6 +33,7 @@
 #include "wildcard.h"
 #include "print.h"
 #include "archive.h"
+#include "operators.h"
 #include "utils.h"
 
 #if EXPAIRSEQ_USE_HASHTAB
@@ -42,7 +43,7 @@
 namespace GiNaC {
 
        
-GINAC_IMPLEMENT_REGISTERED_CLASS_NO_CTORS(expairseq, basic)
+GINAC_IMPLEMENT_REGISTERED_CLASS(expairseq, basic)
 
 //////////
 // helper classes
@@ -58,31 +59,23 @@ public:
 };
 
 //////////
-// 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
@@ -104,11 +97,10 @@ void expairseq::copy(const expairseq &other)
        }
 #endif // EXPAIRSEQ_USE_HASHTAB
 }
-
-DEFAULT_DESTROY(expairseq)
+#endif
 
 //////////
-// other ctors
+// other constructors
 //////////
 
 expairseq::expairseq(const ex &lh, const ex &rh) : inherited(TINFO_expairseq)
@@ -145,16 +137,12 @@ expairseq::expairseq(epvector *vp, const ex &oc)
 // 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))
@@ -162,7 +150,11 @@ expairseq::expairseq(const archive_node &n, const lst &sym_lst) : inherited(n, s
                else
                        break;
        }
+
        n.find_ex("overall_coeff", overall_coeff, sym_lst);
+
+       canonicalize();
+       GINAC_ASSERT(is_canonical());
 }
 
 void expairseq::archive(archive_node &n) const
@@ -185,14 +177,9 @@ DEFAULT_UNARCHIVE(expairseq)
 
 // 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;
 
@@ -200,8 +187,8 @@ void expairseq::print(const print_context &c, unsigned level) const
                    << 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)
@@ -279,7 +266,7 @@ bool expairseq::info(unsigned inf) const
        return inherited::info(inf);
 }
 
-unsigned expairseq::nops() const
+size_t expairseq::nops() const
 {
        if (overall_coeff.is_equal(default_overall_coeff()))
                return seq.size();
@@ -287,19 +274,14 @@ unsigned expairseq::nops() const
                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;
@@ -341,8 +323,8 @@ bool expairseq::match(const ex & pattern, lst & repl_lst) const
                // 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;
@@ -355,12 +337,12 @@ bool expairseq::match(const ex & pattern, lst & repl_lst) const
                // 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;
@@ -381,15 +363,15 @@ found:            ;
                        // 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;
@@ -404,13 +386,15 @@ found:            ;
        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
@@ -545,30 +529,28 @@ bool expairseq::is_equal_same_type(const basic &other) const
 #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);
@@ -685,7 +667,7 @@ bool expairseq::expair_needs_further_processing(epp it)
        return false;
 }
 
-ex expairseq::default_overall_coeff(void) const
+ex expairseq::default_overall_coeff() const
 {
        return _ex0;
 }
@@ -781,8 +763,8 @@ void expairseq::construct_from_2_ex(const ex &lh, const ex &rh)
        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 {
@@ -790,7 +772,7 @@ void expairseq::construct_from_2_ex(const ex &lh, const ex &rh)
                        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 {
@@ -877,7 +859,7 @@ void expairseq::construct_from_expairseq_ex(const expairseq &s,
                                                                                        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;
@@ -1002,7 +984,7 @@ void expairseq::make_flat(const exvector &v)
                                ++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));
@@ -1061,7 +1043,7 @@ void expairseq::make_flat(const epvector &v)
 }
 
 /** 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());
 }
@@ -1070,7 +1052,7 @@ void expairseq::canonicalize(void)
 /** 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;
@@ -1127,7 +1109,7 @@ unsigned expairseq::calc_hashtabsize(unsigned sz) const
        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;
@@ -1136,21 +1118,19 @@ unsigned expairseq::calc_hashtabsize(unsigned sz) const
 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()))) {
@@ -1254,7 +1234,7 @@ void expairseq::build_hashtab_and_combine(epvector::iterator &first_numeric,
        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 {
@@ -1300,7 +1280,7 @@ void expairseq::drop_coeff_0_terms(epvector::iterator &first_numeric,
        // 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;
@@ -1347,7 +1327,7 @@ void expairseq::drop_coeff_0_terms(epvector::iterator &first_numeric,
 /** 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) {
@@ -1370,7 +1350,7 @@ void expairseq::add_numerics_to_hashtab(epvector::iterator first_numeric,
        }
 }
 
-void expairseq::combine_same_terms(void)
+void expairseq::combine_same_terms()
 {
        // combine same terms, drop term with coeff 0, move numerics to end
        
@@ -1396,7 +1376,7 @@ void expairseq::combine_same_terms(void)
        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;
@@ -1442,11 +1422,11 @@ bool expairseq::is_canonical() const
        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);
@@ -1566,7 +1546,7 @@ epvector * expairseq::evalchildren(int level) const
  *  @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());
 
@@ -1574,11 +1554,12 @@ epvector * expairseq::subschildren(const lst &ls, const lst &lr, bool no_pattern
        // 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) {
 
@@ -1587,7 +1568,7 @@ epvector * expairseq::subschildren(const lst &ls, const lst &lr, bool no_pattern
                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
@@ -1603,7 +1584,7 @@ epvector * expairseq::subschildren(const lst &ls, const lst &lr, bool no_pattern
 
                                // 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;
@@ -1618,7 +1599,7 @@ epvector * expairseq::subschildren(const lst &ls, const lst &lr, bool no_pattern
                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
@@ -1634,7 +1615,7 @@ epvector * expairseq::subschildren(const lst &ls, const lst &lr, bool no_pattern
 
                                // 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;
                                }
index 13e0d161312d89fa38e98a3418f597b6e6124caf..f1086353a5fb07b1b9bf848c54633d76ad81660a 100644 (file)
@@ -59,24 +59,9 @@ typedef std::vector<epplist> epplistvector; ///< vector of epplist
  *  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);
@@ -85,23 +70,21 @@ public:
        
        // 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
@@ -120,7 +103,7 @@ protected:
                                                                                                   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;
@@ -137,13 +120,13 @@ protected:
        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);
@@ -156,14 +139,14 @@ protected:
                                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
        
similarity index 75%
rename from ginac/exprseq_suppl.cpp
rename to ginac/exprseq.cpp
index 29bb549ad61caa66e07d0fc747a48966390ff57b..9593b2c61103e99f4e7105560a408ec6ffb11c3f 100644 (file)
@@ -1,7 +1,6 @@
-/** @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
diff --git a/ginac/exprseq.h b/ginac/exprseq.h
new file mode 100644 (file)
index 0000000..31b2e77
--- /dev/null
@@ -0,0 +1,48 @@
+/** @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__
index fc539ab5f7f6a9680f146d03c1e8771077cd11da..92aaa102dd26a452593b1263845d303bebc8723b 100644 (file)
@@ -33,10 +33,10 @@ namespace GiNaC {
 GINAC_IMPLEMENT_REGISTERED_CLASS(fail, basic)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
-DEFAULT_CTORS(fail)
+DEFAULT_CTOR(fail)
 
 //////////
 // archiving
index a681d5598ccfa1734abfa8eb9bfd3b892b7b7237..a537fa0491214480e99a2e9b4e03b43d27d7e882 100644 (file)
@@ -36,7 +36,7 @@ class fail : public basic
 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. */
index 20070b84c90eecc94f4f5ffa657ddca52bb37c6a..4a93de49e1a181213dda30e639a3cc075bf9d1bf 100644 (file)
@@ -23,6 +23,7 @@
 #include <iostream>
 
 #include "fderivative.h"
+#include "operators.h"
 #include "print.h"
 #include "archive.h"
 #include "utils.h"
@@ -32,7 +33,7 @@ namespace GiNaC {
 GINAC_IMPLEMENT_REGISTERED_CLASS(fderivative, function)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
 fderivative::fderivative()
@@ -40,14 +41,6 @@ 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
 //////////
@@ -72,7 +65,7 @@ fderivative::fderivative(unsigned ser, const paramset & params, exvector * vp) :
 // 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) {
@@ -116,7 +109,7 @@ void fderivative::print(const print_context & c, unsigned level) const
                        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;
 
@@ -164,12 +157,12 @@ ex fderivative::series(const relational & r, int order, unsigned options) const
        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);
 }
@@ -179,7 +172,7 @@ ex fderivative::thisexprseq(exvector * vp) const
 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;
index 3b82ad39baf059da7deb6078aa662555b0cf120e..3e335beebcd36802ebb52c8561a2bc14ebed2860 100644 (file)
@@ -64,8 +64,8 @@ public:
        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;
index 62cd82a4e0840a9c9ae2e241aded65ca7dccfcc7..04c430c4caae87540983a6bfae53a4341430774a 100644 (file)
@@ -25,6 +25,7 @@
 
 namespace GiNaC {
 
+/** Flags to control the behavior of expand(). */
 class expand_options {
 public:
        enum {
@@ -34,10 +35,23 @@ public:
        };
 };
 
+/** 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
        };
 };
@@ -46,11 +60,52 @@ public:
 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
        };
 };
 
@@ -58,10 +113,48 @@ public:
 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
        };
 };
 
index 727eb52ff683cd386e5c1e0d221f54d302502487..4d19e6295897a3ed19b7d70e103d39de13e9fe7a 100755 (executable)
@@ -39,10 +39,9 @@ sub generate {
 $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
@@ -197,7 +196,7 @@ $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 {
@@ -224,6 +223,7 @@ typedef ex (* evalf_funcp_exvector)(const exvector &);
 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;
@@ -232,7 +232,7 @@ public:
        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
@@ -247,15 +247,15 @@ $series_func_interface
        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;
@@ -289,6 +289,12 @@ protected:
        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
@@ -297,7 +303,7 @@ 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;
@@ -306,7 +312,7 @@ class function : public exprseq
 
 // member functions
 
-       // other ctors
+       // other constructors
 public:
        function(unsigned ser);
        // the following lines have been generated for max. ${maxargs} parameters
@@ -319,20 +325,20 @@ $constructors_interface
        // 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
@@ -340,15 +346,15 @@ protected:
        // 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
 
@@ -364,8 +370,15 @@ template<> inline bool is_exactly_a<function>(const basic & obj)
        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
 
@@ -406,6 +419,7 @@ $implementation=<<END_OF_IMPLEMENTATION;
 #include <list>
 
 #include "function.h"
+#include "operators.h"
 #include "fderivative.h"
 #include "ex.h"
 #include "lst.h"
@@ -439,7 +453,7 @@ function_options::~function_options()
        // nothing to clean up at the moment
 }
 
-void function_options::initialize(void)
+void function_options::initialize()
 {
        set_name("unnamed_function","\\\\mbox{unnamed}");
        nparams = 0;
@@ -512,7 +526,7 @@ function_options & function_options::set_return_type(unsigned rt, unsigned rtt)
        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;
@@ -549,7 +563,7 @@ void function_options::test_and_set_nparams(unsigned n)
                // 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;
        }
@@ -562,7 +576,7 @@ unsigned function::current_serial = 0;
 GINAC_IMPLEMENT_REGISTERED_CLASS(function, exprseq)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
 // public
@@ -572,22 +586,8 @@ function::function() : serial(0)
        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
@@ -627,7 +627,7 @@ function::function(unsigned ser, exvector * vp)
 //////////
 
 /** 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;
@@ -647,7 +647,7 @@ function::function(const archive_node &n, const lst &sym_lst) : inherited(n, sym
 }
 
 /** 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);
 }
@@ -670,7 +670,7 @@ void function::print(const print_context & c, unsigned level) const
 {
        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
@@ -678,16 +678,16 @@ void function::print(const print_context & c, unsigned level) const
                    << ", 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 << "(";
 
@@ -701,7 +701,7 @@ void function::print(const print_context & c, unsigned level) const
                }
                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 {
@@ -739,7 +739,7 @@ ex function::eval(int level) const
                        // Something has changed while sorting arguments, more evaluations later
                        if (sig == 0)
                                return _ex0;
-                       return ex(sig) * thisexprseq(v);
+                       return ex(sig) * thiscontainer(v);
                }
        }
 
@@ -805,14 +805,14 @@ ${evalf_switch_statement}
        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;
@@ -820,12 +820,12 @@ unsigned function::calchash(void) const
        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);
 }
@@ -866,14 +866,14 @@ ex function::derivative(const symbol & s) const
 {
        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
@@ -889,7 +889,7 @@ ex function::derivative(const symbol & s) const
 
 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)
@@ -900,7 +900,7 @@ int function::compare_same_type(const basic & other) const
 
 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)
@@ -911,13 +911,13 @@ bool function::is_equal_same_type(const basic & other) const
 
 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];
 
@@ -934,7 +934,7 @@ unsigned function::return_type(void) const
        }
 }
 
-unsigned function::return_type_tinfo(void) const
+unsigned function::return_type_tinfo() const
 {
        const function_options &opt = registered_functions()[serial];
 
@@ -982,7 +982,7 @@ ${diff_switch_statement}
        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;
@@ -1002,8 +1002,8 @@ void function::store_remember_table(ex const & result) const
 
 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;
                }
@@ -1043,7 +1043,7 @@ unsigned function::find_function(const std::string &name, unsigned nparams)
 }
 
 /** 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;
index f69613c69065652569bc7adeb524e0f6ac6bf4e7..265c107557eba27135ab31fdad2c36bdddd29650 100644 (file)
@@ -28,6 +28,7 @@
 #include "symbol.h"
 #include "lst.h"
 #include "relational.h"
+#include "operators.h"
 #include "print.h"
 #include "archive.h"
 #include "utils.h"
@@ -39,7 +40,7 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(varidx, idx)
 GINAC_IMPLEMENT_REGISTERED_CLASS(spinidx, varidx)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
 idx::idx() : inherited(TINFO_idx) {}
@@ -54,29 +55,6 @@ spinidx::spinidx() : dotted(false)
        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
 //////////
@@ -102,18 +80,18 @@ spinidx::spinidx(const ex & v, const ex & d, bool cov, bool dot) : inherited(v,
 // 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);
 }
@@ -147,7 +125,7 @@ DEFAULT_UNARCHIVE(spinidx)
 
 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
@@ -168,6 +146,11 @@ void idx::print(const print_context & c, unsigned level) const
                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 << "}";
        }
@@ -175,7 +158,7 @@ void idx::print(const print_context & c, unsigned level) const
 
 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
@@ -200,6 +183,11 @@ void varidx::print(const print_context & c, unsigned level) const
                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 << "}";
        }
@@ -207,7 +195,7 @@ void varidx::print(const print_context & c, unsigned level) const
 
 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
@@ -220,7 +208,7 @@ void spinidx::print(const print_context & c, unsigned level) const
 
        } 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 << "_{";
@@ -258,18 +246,27 @@ bool idx::info(unsigned inf) const
        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
@@ -303,6 +300,7 @@ int varidx::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;
 }
 
@@ -313,6 +311,7 @@ bool varidx::match_same_type(const basic & other) const
 
        if (covariant != o.covariant)
                return false;
+
        return inherited::match_same_type(other);
 }
 
@@ -349,32 +348,33 @@ ex idx::evalf(int level) const
        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);
@@ -396,8 +396,7 @@ bool idx::is_dummy_pair_same_type(const basic & other) const
 {
        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;
 
@@ -442,7 +441,7 @@ bool spinidx::is_dummy_pair_same_type(const basic & other) const
 
 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);
@@ -453,25 +452,25 @@ ex idx::minimal_dim(const idx & other) const
        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);
index 3811a4efe400123bc1d0f63303b87ec36ef3fc7b..bb74ddac24a0e8e0d7607711166425ac6d28c50c 100644 (file)
@@ -50,10 +50,11 @@ public:
 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;
@@ -68,22 +69,22 @@ public:
        // 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;
@@ -125,13 +126,13 @@ protected:
        // 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:
@@ -170,18 +171,18 @@ 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:
@@ -248,7 +249,7 @@ inline void find_dummy_indices(const exvector & v, exvector & out_dummy)
 }
 
 /** 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);
@@ -256,7 +257,7 @@ inline unsigned count_dummy_indices(const exvector & v)
 }
 
 /** 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);
index 81230c4d7ff1365822d9831ac6a6c562bc8ecc01..c899e13cd7f237580b11ae8becb5bb9474b7645c 100644 (file)
@@ -32,6 +32,7 @@
 #include "power.h"
 #include "relational.h"
 #include "symmetry.h"
+#include "operators.h"
 #include "lst.h"
 #include "print.h"
 #include "archive.h"
@@ -42,7 +43,7 @@ namespace GiNaC {
 GINAC_IMPLEMENT_REGISTERED_CLASS(indexed, exprseq)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
 indexed::indexed() : symtree(sy_none())
@@ -50,14 +51,6 @@ 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
 //////////
@@ -143,7 +136,7 @@ indexed::indexed(const symmetry & symm, exvector * vp) : inherited(vp), symtree(
 // 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
@@ -250,11 +243,11 @@ ex indexed::eval(int level) const
                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
@@ -266,7 +259,7 @@ ex indexed::eval(int level) const
                        // Something has changed while sorting indices, more evaluations later
                        if (sig == 0)
                                return _ex0;
-                       return ex(sig) * thisexprseq(v);
+                       return ex(sig) * thiscontainer(v);
                }
        }
 
@@ -274,12 +267,12 @@ ex indexed::eval(int level) const
        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);
 }
@@ -288,15 +281,15 @@ ex indexed::expand(unsigned options) const
 {
        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;
 
@@ -327,7 +320,7 @@ void indexed::printindices(const print_context & c, unsigned level) const
                        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)
@@ -359,18 +352,18 @@ void indexed::printindices(const print_context & c, unsigned level) const
 /** 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);
        }
@@ -414,13 +407,13 @@ static bool indices_consistent(const exvector & v1, const exvector & v2)
        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);
@@ -448,17 +441,17 @@ bool indexed::has_dummy_index_for(const ex & i) const
        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 {
@@ -470,11 +463,11 @@ exvector add::get_free_indices(void) const
        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());
        }
@@ -485,11 +478,11 @@ exvector mul::get_free_indices(void) const
        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());
        }
@@ -500,7 +493,7 @@ exvector ncmul::get_free_indices(void) const
        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();
@@ -516,8 +509,8 @@ exvector power::get_free_indices(void) const
  *    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)
@@ -527,7 +520,7 @@ static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, ex
 
                // 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) {
@@ -545,19 +538,21 @@ static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, ex
        }
        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())
@@ -565,7 +560,7 @@ static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, ex
        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()));
        }
 }
 
@@ -649,27 +644,27 @@ ex simplify_indexed_product(const ex & e, exvector & free_indices, exvector & du
 {
        // 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);
@@ -683,7 +678,7 @@ ex simplify_indexed_product(const ex & e, exvector & free_indices, exvector & du
        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);
@@ -696,7 +691,7 @@ try_again:
                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);
@@ -710,15 +705,32 @@ try_again:
                        // 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;
                                }
@@ -735,14 +747,14 @@ try_again:
                        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);
@@ -762,7 +774,7 @@ contraction_done:
        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());
@@ -790,7 +802,7 @@ contraction_done:
 
                // 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))
@@ -808,10 +820,11 @@ contraction_done:
        // 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;
                }
@@ -821,8 +834,8 @@ contraction_done:
        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;
@@ -852,7 +865,7 @@ class symminfo {
 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);
@@ -866,7 +879,7 @@ public:
        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 {
@@ -893,7 +906,7 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
 
        // 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);
@@ -918,12 +931,12 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
 
        // 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()) {
@@ -938,7 +951,7 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
                                                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;
@@ -953,21 +966,22 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
                }
 
                // 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));
@@ -979,7 +993,7 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
                // 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++;
@@ -997,8 +1011,8 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
                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));
@@ -1045,7 +1059,7 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
                        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++;
@@ -1077,9 +1091,9 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
        }
 
        // 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
@@ -1092,7 +1106,7 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
  *  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;
@@ -1113,19 +1127,19 @@ ex ex::simplify_indexed(const scalar_products & sp) const
 }
 
 /** 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());
 }
@@ -1134,65 +1148,101 @@ ex ex::symmetrize_cyclic(void) const
 // 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
index 0a00e76999d93cb4328ffea566903f17d55c072d..21947ff03728994518d4d0189b44e9b793805b63 100644 (file)
@@ -26,6 +26,7 @@
 #include <map>
 
 #include "exprseq.h"
+#include "wildcard.h"
 
 namespace GiNaC {
 
@@ -144,16 +145,16 @@ public:
        // 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
@@ -166,10 +167,10 @@ public:
        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. */
@@ -180,11 +181,11 @@ public:
        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:
@@ -192,17 +193,21 @@ 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().
@@ -213,21 +218,22 @@ public:
        /** 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 */
 };
 
index 9d373e794a7313d2c68ce5c27381cb0bb8fd49e1..73f9c22111d13cead3d7f4082e83691695e49863 100644 (file)
@@ -30,6 +30,7 @@
 #include "matrix.h"
 #include "mul.h"
 #include "power.h"
+#include "operators.h"
 #include "relational.h"
 #include "pseries.h"
 #include "symbol.h"
@@ -52,7 +53,7 @@ static ex abs_evalf(const ex & arg)
 
 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();
@@ -76,11 +77,11 @@ static ex csgn_evalf(const ex & arg)
 
 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)
@@ -323,7 +324,7 @@ static ex Li2_series(const ex &x, const relational &rel, int order, unsigned opt
                        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));
@@ -365,7 +366,7 @@ static ex factorial_evalf(const ex & x)
 
 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();
@@ -385,7 +386,7 @@ static ex binomial_evalf(const ex & x, const ex & y)
 
 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();
@@ -400,16 +401,16 @@ REGISTER_FUNCTION(binomial, eval_func(binomial_eval).
 
 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();
@@ -453,7 +454,7 @@ ex lsolve(const ex &eqns, const ex &symbols, unsigned options)
        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"));
                }
@@ -461,7 +462,7 @@ ex lsolve(const ex &eqns, const ex &symbols, unsigned options)
        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"));
                }
@@ -472,10 +473,10 @@ ex lsolve(const ex &eqns, const ex &symbols, unsigned options)
        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;
@@ -485,7 +486,7 @@ ex lsolve(const ex &eqns, const ex &symbols, unsigned options)
        }
        
        // 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"));
@@ -506,7 +507,7 @@ ex lsolve(const ex &eqns, const ex &symbols, unsigned options)
        
        // 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;
@@ -514,7 +515,7 @@ ex lsolve(const ex &eqns, const ex &symbols, unsigned options)
 
 /* 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
index 11850c34896a563d935b52807e1a4a372ab4fa07..f4c00dd0e7041d9d18c08dfcda96f050a9537cab 100644 (file)
@@ -90,16 +90,21 @@ DECLARE_FUNCTION_1P(Li3)
 
 // 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. */
@@ -111,16 +116,21 @@ DECLARE_FUNCTION_2P(beta)
 
 // 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. */
@@ -132,7 +142,7 @@ DECLARE_FUNCTION_2P(binomial)
 /** 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)
index 3f3bd561bc4a54c85dd1f1a9eb912216eb6ff782..fc4a992c97acc6db876bbb1c61ac9818fd0c21eb 100644 (file)
@@ -30,6 +30,7 @@
 #include "numeric.h"
 #include "power.h"
 #include "relational.h"
+#include "operators.h"
 #include "symbol.h"
 #include "symmetry.h"
 #include "utils.h"
@@ -230,6 +231,10 @@ static ex beta_evalf(const ex & x, const ex & y)
 
 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
@@ -417,7 +422,7 @@ static ex psi1_series(const ex & arg,
        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).
@@ -545,7 +550,7 @@ static ex psi2_series(const ex & n,
        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).
index 67a578dd72b4f1963b752cf2359ba8af9b5ce839..79d7cd473de2c0dcc0f07190a709d8feab9535b4 100644 (file)
@@ -29,6 +29,7 @@
 #include "constant.h"
 #include "numeric.h"
 #include "power.h"
+#include "operators.h"
 #include "relational.h"
 #include "symbol.h"
 #include "pseries.h"
@@ -141,14 +142,6 @@ static ex log_deriv(const ex & x, unsigned deriv_param)
        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,
index ef956e61f740a467b55a2fe1bab394830112ae38..365f35e22aeb9501541b8fb559a9d44168d171c0 100644 (file)
@@ -28,6 +28,7 @@
 #include "numeric.h"
 #include "power.h"
 #include "symbol.h"
+#include "operators.h"
 #include "utils.h"
 
 namespace GiNaC {
@@ -83,7 +84,7 @@ static ex zeta1_deriv(const ex & x, unsigned deriv_param)
        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).
@@ -118,7 +119,7 @@ static ex zeta2_deriv(const ex & n, const ex & x, unsigned deriv_param)
        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).
index 001c546745d787d58fe032a52dc4fef43258b597..53ef018674ad1a7d063da400f6f88c243899ab82 100644 (file)
@@ -60,7 +60,7 @@ extern void set_lexer_symbols(ex l);
 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;
index c4f69c26d39aeb7c13121242d4a23c59de7ce938..9f22814dc95a38350082083c151c8914351fde21 100644 (file)
 %{
 #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"
similarity index 79%
rename from ginac/lst_suppl.cpp
rename to ginac/lst.cpp
index 7c0d83fc91c3f5fe03e8f2c41b7c4143482d0509..566d16b172f9cc9081b84db060aee1113b2aaf88 100644 (file)
@@ -1,7 +1,6 @@
-/** @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
diff --git a/ginac/lst.h b/ginac/lst.h
new file mode 100644 (file)
index 0000000..d4e8091
--- /dev/null
@@ -0,0 +1,54 @@
+/** @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__
index d82abab790356326efc060b7f88749285ad88c49..990da8391138708ed5af986bfdfd5805871831ff 100644 (file)
 #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"
@@ -44,7 +46,7 @@ namespace GiNaC {
 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. */
@@ -53,18 +55,8 @@ matrix::matrix() : inherited(TINFO_matrix), row(1), col(1)
        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
@@ -94,12 +86,13 @@ matrix::matrix(unsigned r, unsigned c, const lst & l)
 {
        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;
        }
 }
 
@@ -107,7 +100,7 @@ matrix::matrix(unsigned r, unsigned c, const lst & l)
 // 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"));
@@ -192,23 +185,25 @@ void matrix::print(const print_context & c, unsigned level) const
 }
 
 /** 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];
 }
 
@@ -234,14 +229,14 @@ ex matrix::eval(int level) const
                                                                                           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
@@ -367,7 +362,7 @@ ex matrix::add_indexed(const ex & self, const ex & other) const
        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));
@@ -418,7 +413,7 @@ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, ex
        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);
@@ -607,7 +602,7 @@ matrix matrix::pow(const ex & expn) const
        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)) {
@@ -675,7 +670,7 @@ ex & matrix::operator() (unsigned ro, unsigned co)
 
 /** 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());
        
@@ -832,7 +827,7 @@ ex matrix::determinant(unsigned algo) const
  *
  *  @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"));
@@ -877,6 +872,7 @@ ex matrix::charpoly(const symbol & lambda) const
        // 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);
@@ -884,20 +880,22 @@ ex matrix::charpoly(const symbol & lambda) const
                        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);
+       }
 }
 
 
@@ -906,7 +904,7 @@ ex matrix::charpoly(const symbol & lambda) const
  *  @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"));
@@ -1057,7 +1055,7 @@ matrix matrix::solve(const matrix & vars,
  *
  *  @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();
@@ -1290,7 +1288,7 @@ int matrix::fraction_free_elimination(const bool det)
        //
        // 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
@@ -1449,34 +1447,45 @@ int matrix::pivot(unsigned ro, unsigned co, bool symbolic)
 
 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)
index 4dc2ee0584e1cad9c78fcf3752700093da75e305..d0d9d7d1e075c245d59fc416e34ffbd44c982197 100644 (file)
@@ -35,7 +35,7 @@ class matrix : public basic
 {
        GINAC_DECLARE_REGISTERED_CLASS(matrix, basic)
        
-       // other ctors
+       // other constructors
 public:
        matrix(unsigned r, unsigned c);
        matrix(unsigned r, unsigned c, const exvector & m2);
@@ -44,12 +44,12 @@ public:
        // 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;
@@ -57,13 +57,13 @@ public:
 
 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;
@@ -74,15 +74,15 @@ public:
        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);
@@ -98,7 +98,7 @@ protected:
 
 // 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)
index 4a66f310ccf0aaf6eb335898a2424ecd8a2b2834..8fe739987274e6d93dc8449f6fa5be1ed5992881 100644 (file)
 #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"
 
@@ -36,7 +39,7 @@ namespace GiNaC {
 GINAC_IMPLEMENT_REGISTERED_CLASS(mul, expairseq)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
 mul::mul()
@@ -44,11 +47,8 @@ mul::mul()
        tinfo_key = TINFO_mul;
 }
 
-DEFAULT_COPY(mul)
-DEFAULT_DESTROY(mul)
-
 //////////
-// other ctors
+// other constructors
 //////////
 
 // public
@@ -119,7 +119,6 @@ DEFAULT_ARCHIVING(mul)
 //////////
 
 // public
-
 void mul::print(const print_context & c, unsigned level) const
 {
        if (is_a<print_tree>(c)) {
@@ -154,10 +153,10 @@ void mul::print(const print_context & c, unsigned level) const
                        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)
@@ -179,7 +178,7 @@ void mul::print(const print_context & c, unsigned level) const
        } 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);
                }
@@ -194,7 +193,7 @@ void mul::print(const print_context & c, unsigned level) const
                }
 
                // 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) &&
@@ -392,7 +391,7 @@ ex mul::eval(int level) const
                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 */
@@ -421,7 +420,7 @@ ex mul::eval(int level) const
                // *(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);
@@ -461,11 +460,11 @@ ex mul::evalf(int level) const
        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
@@ -481,7 +480,7 @@ ex mul::evalm(void) const
        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;
                }
@@ -501,19 +500,144 @@ ex mul::evalm(void) const
                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
@@ -522,7 +646,7 @@ ex mul::simplify_ncmul(const exvector & v) const
  *  @see ex::diff */
 ex mul::derivative(const symbol & s) const
 {
-       unsigned num = seq.size();
+       size_t num = seq.size();
        exvector addseq;
        addseq.reserve(num);
        
@@ -546,12 +670,7 @@ int mul::compare_same_type(const basic & other) const
        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
@@ -584,7 +703,7 @@ unsigned mul::return_type(void) const
        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
@@ -612,9 +731,9 @@ ex mul::thisexpairseq(epvector * vp, const ex & oc) const
 
 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);
@@ -625,11 +744,11 @@ expair mul::combine_ex_with_coeff_to_pair(const ex & e,
 {
        // 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));
 }
        
@@ -638,11 +757,11 @@ expair mul::combine_pair_with_coeff_to_pair(const expair & p,
 {
        // 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));
 }
        
@@ -651,25 +770,25 @@ ex mul::recombine_pair_to_ex(const expair & p) const
        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;
                }
@@ -677,7 +796,7 @@ bool mul::expair_needs_further_processing(epp it)
        return false;
 }       
 
-ex mul::default_overall_coeff(void) const
+ex mul::default_overall_coeff() const
 {
        return _ex1;
 }
@@ -721,30 +840,11 @@ ex mul::expand(unsigned options) const
        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%!
@@ -788,7 +888,7 @@ ex mul::expand(unsigned options) const
                                                // 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))));
@@ -796,7 +896,7 @@ ex mul::expand(unsigned options) const
                                        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;
@@ -811,12 +911,12 @@ ex mul::expand(unsigned options) const
        
        // 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))->
index d7df44a964cc961c6f891339866a427b360f388a..01fb205631cddd35765ac70da49774a5b0514980 100644 (file)
@@ -36,7 +36,7 @@ class mul : public expairseq
        friend class ncmul;
        friend class power;
        
-       // other ctors
+       // other constructors
 public:
        mul(const ex & lh, const ex & rh);
        mul(const exvector & v);
@@ -48,26 +48,25 @@ public:
        // 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;
@@ -75,7 +74,7 @@ protected:
        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;
@@ -85,6 +84,8 @@ protected:
        // 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;
 };
index 2b91cb23dd44853906dc64dd32adbdfb8136378a..dd0c7bdc07d0fee84c03ade49504b13375c16a3c 100644 (file)
@@ -38,7 +38,7 @@ namespace GiNaC {
 GINAC_IMPLEMENT_REGISTERED_CLASS(ncmul, exprseq)
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
 ncmul::ncmul()
@@ -46,9 +46,6 @@ ncmul::ncmul()
        tinfo_key = TINFO_ncmul;
 }
 
-DEFAULT_COPY(ncmul)
-DEFAULT_DESTROY(ncmul)
-
 //////////
 // other constructors
 //////////
@@ -144,15 +141,15 @@ ex ncmul::expand(unsigned options) const
        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++;
@@ -174,7 +171,7 @@ ex ncmul::expand(unsigned options) const
 
        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)));
@@ -251,12 +248,12 @@ ex ncmul::coeff(const ex & s, int n) const
        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;
@@ -266,10 +263,10 @@ unsigned ncmul::count_factors(const ex & e) const
                
 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);
 }
@@ -285,7 +282,7 @@ typedef std::vector<exvector> exvectorvector;
  *  - 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
@@ -305,7 +302,7 @@ 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++);
@@ -325,10 +322,10 @@ ex ncmul::eval(int level) const
        // 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()) {
@@ -355,8 +352,8 @@ ex ncmul::eval(int level) const
                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
@@ -374,7 +371,7 @@ ex ncmul::eval(int level) const
                // 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);
@@ -383,7 +380,7 @@ ex ncmul::eval(int level) const
                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]) {
@@ -401,11 +398,11 @@ ex ncmul::eval(int level) const
                        ++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);
@@ -413,7 +410,7 @@ ex ncmul::eval(int level) const
                
                // 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);
@@ -427,7 +424,7 @@ ex ncmul::eval(int level) const
                                                                                  status_flags::evaluated);
 }
 
-ex ncmul::evalm(void) const
+ex ncmul::evalm() const
 {
        // Evaluate children first
        exvector *s = new exvector;
@@ -440,11 +437,11 @@ ex ncmul::evalm(void) const
 
        // 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++;
@@ -457,12 +454,12 @@ no_matrix:
        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);
 }
@@ -474,13 +471,13 @@ ex ncmul::thisexprseq(exvector * vp) const
  *  @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));
@@ -494,7 +491,7 @@ int ncmul::compare_same_type(const basic & other) const
        return inherited::compare_same_type(other);
 }
 
-unsigned ncmul::return_type(void) const
+unsigned ncmul::return_type() const
 {
        if (seq.empty())
                return return_types::commutative;
@@ -526,7 +523,7 @@ unsigned ncmul::return_type(void) const
        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;
@@ -565,7 +562,7 @@ exvector ncmul::expandchildren(unsigned options) const
        return s;
 }
 
-const exvector & ncmul::get_factors(void) const
+const exvector & ncmul::get_factors() const
 {
        return seq;
 }
@@ -574,12 +571,12 @@ const exvector & ncmul::get_factors(void) const
 // 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;
index 78a45ed6d65db00ae4635391df781f07c58bf6e1..072ebfbbd13ea19cac4cfd45856c2e7771ca820d 100644 (file)
@@ -33,8 +33,8 @@ class ncmul : public exprseq
        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
 
@@ -54,38 +54,39 @@ public:
        // 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
 
index 5139509c51c59835947a0bef3d9dcd9bb51da049..cd2ad8eca5a0b29024bc142e81c19866f031bea7 100644 (file)
@@ -39,6 +39,7 @@
 #include "numeric.h"
 #include "power.h"
 #include "relational.h"
+#include "operators.h"
 #include "matrix.h"
 #include "pseries.h"
 #include "symbol.h"
@@ -96,7 +97,7 @@ static bool get_first_symbol(const ex &e, const symbol *&x)
                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)) {
@@ -137,7 +138,7 @@ struct sym_desc {
        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
@@ -172,7 +173,7 @@ static void collect_symbols(const ex &e, sym_desc_vec &v)
        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);
@@ -208,6 +209,7 @@ static void get_symbol_stats(const ex &a, const ex &b, sym_desc_vec &v)
                ++it;
        }
        std::sort(v.begin(), v.end());
+
 #if 0
        std::clog << "Symbols:\n";
        it = v.begin(); itend = v.end();
@@ -232,12 +234,12 @@ static numeric lcmcoeff(const ex &e, const numeric &l)
                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)) {
@@ -269,10 +271,10 @@ static numeric lcm_of_coefficients_denominators(const ex &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;
@@ -280,9 +282,9 @@ static ex multiply_lcm(const ex &e, const numeric &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)) {
@@ -300,23 +302,22 @@ static ex multiply_lcm(const ex &e, const numeric &lcm)
  *
  *  @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();
@@ -332,7 +333,7 @@ numeric add::integer_content(void) const
        return c;
 }
 
-numeric mul::integer_content(void) const
+numeric mul::integer_content() const
 {
 #ifdef DO_GINAC_ASSERT
        epvector::const_iterator it = seq.begin();
@@ -922,206 +923,6 @@ ex ex::primpart(const symbol &x, const ex &c) const
  *  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().
  *
@@ -1133,7 +934,6 @@ static ex red_gcd(const ex &a, const ex &b, const symbol *x)
 
 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
@@ -1165,22 +965,20 @@ static ex sr_gcd(const ex &a, const ex &b, sym_desc_vec::const_iterator var)
                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);
@@ -1192,7 +990,6 @@ static ex sr_gcd(const ex &a, const ex &b, sym_desc_vec::const_iterator var)
                }
 
                // Next element of subresultant sequence
-//std::clog << " calculating next subresultant...\n";
                ri = c.expand().lcoeff(x);
                if (delta == 1)
                        psi = ri;
@@ -1209,25 +1006,24 @@ static ex sr_gcd(const ex &a, const ex &b, sym_desc_vec::const_iterator var)
  *  @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();
@@ -1244,7 +1040,7 @@ numeric add::max_coefficient(void) const
        return cur_max;
 }
 
-numeric mul::max_coefficient(void) const
+numeric mul::max_coefficient() const
 {
 #ifdef DO_GINAC_ASSERT
        epvector::const_iterator it = seq.begin();
@@ -1346,7 +1142,6 @@ class gcdheu_failed {};
  *  @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
@@ -1387,7 +1182,6 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const
        // 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();
                }
 
@@ -1412,34 +1206,6 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const
                                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
@@ -1459,7 +1225,6 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const
  *  @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
@@ -1493,11 +1258,11 @@ ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args)
                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);
@@ -1512,11 +1277,11 @@ factored_a:
                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);
@@ -1621,20 +1386,17 @@ factored_b:
        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)
@@ -1642,25 +1404,17 @@ factored_b:
                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
@@ -1674,7 +1428,6 @@ factored_b:
                        if (cb)
                                divide(bex, g, *cb, false);
                }
-#if 1
        } else {
                if (g.is_equal(_ex1)) {
                        // Keep cofactors factored if possible
@@ -1684,7 +1437,7 @@ factored_b:
                                *cb = b;
                }
        }
-#endif
+
        return g;
 }
 
@@ -1800,7 +1553,7 @@ ex sqrfree(const ex &a, const lst &l)
        }
 
        // 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));
 
@@ -1865,15 +1618,15 @@ ex sqrfree_parfrac(const ex & a, const symbol & x)
        // 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
@@ -1883,7 +1636,7 @@ ex sqrfree_parfrac(const ex & a, const symbol & x)
                        }
                }
        }
-       unsigned num_factors = factor.size();
+       size_t num_factors = factor.size();
 //clog << "factors  : " << exprseq(factor) << endl;
 //clog << "cofactors: " << exprseq(cofac) << endl;
 
@@ -1892,7 +1645,7 @@ ex sqrfree_parfrac(const ex & a, const symbol & x)
        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);
        }
@@ -1901,13 +1654,13 @@ ex sqrfree_parfrac(const ex & a, const symbol & x)
 
        // 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;
@@ -1934,9 +1687,10 @@ ex sqrfree_parfrac(const ex & a, const symbol & x)
 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
@@ -1952,13 +1706,14 @@ static ex replace_with_symbol(const ex &e, lst &sym_lst, lst &repl_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
@@ -2288,7 +2043,7 @@ ex ex::normal(int level) const
  *
  *  @see ex::normal
  *  @return numerator */
-ex ex::numer(void) const
+ex ex::numer() const
 {
        lst sym_lst, repl_lst;
 
@@ -2308,7 +2063,7 @@ ex ex::numer(void) const
  *
  *  @see ex::normal
  *  @return denominator */
-ex ex::denom(void) const
+ex ex::denom() const
 {
        lst sym_lst, repl_lst;
 
@@ -2328,7 +2083,7 @@ ex ex::denom(void) const
  *
  *  @see ex::normal
  *  @return a list [numerator, denominator] */
-ex ex::numer_denom(void) const
+ex ex::numer_denom() const
 {
        lst sym_lst, repl_lst;
 
@@ -2344,7 +2099,7 @@ ex ex::numer_denom(void) const
 
 
 /** 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()
@@ -2357,11 +2112,29 @@ ex ex::numer_denom(void) const
  *
  *  @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. */
@@ -2370,6 +2143,13 @@ ex symbol::to_rational(lst &repl_lst) const
        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
@@ -2389,6 +2169,24 @@ ex numeric::to_rational(lst &repl_lst) const
        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. */
@@ -2400,6 +2198,16 @@ ex power::to_rational(lst &repl_lst) const
                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
@@ -2419,6 +2227,24 @@ 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
@@ -2427,13 +2253,13 @@ static ex find_common_factor(const ex & e, ex & factor, lst & repl)
 {
        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;
@@ -2456,16 +2282,16 @@ static ex find_common_factor(const ex & e, ex & factor, lst & repl)
                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
@@ -2485,21 +2311,17 @@ term_done:      ;
 
        } 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;
index a299d20cfbdf7b08a64dca20cb51999ed76944d4..c69a117d3748c0da1ed9fd26385143b5529a2361 100644 (file)
 #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"
@@ -62,7 +64,7 @@ namespace GiNaC {
 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. */
@@ -72,16 +74,8 @@ numeric::numeric() : basic(TINFO_numeric)
        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
@@ -243,7 +237,7 @@ numeric::numeric(const cln::cl_N &z) : basic(TINFO_numeric)
 // 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;
 
@@ -456,9 +450,9 @@ void numeric::print(const print_context & c, unsigned level) const
 
                // 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()) {
 
@@ -618,7 +612,7 @@ ex numeric::coeff(const ex & s, int n) const
  *  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))
@@ -680,13 +674,15 @@ bool numeric::is_equal_same_type(const basic &other) const
 }
 
 
-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;
 }
 
 
@@ -706,12 +702,6 @@ unsigned numeric::calchash(void) const
  *  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));
 }
 
@@ -728,12 +718,6 @@ const numeric numeric::sub(const numeric &other) const
  *  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));
 }
 
@@ -754,8 +738,9 @@ const numeric numeric::div(const numeric &other) const
  *  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))) {
@@ -772,52 +757,87 @@ const numeric numeric::power(const numeric &other) const
 }
 
 
+
+/** 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))) {
@@ -872,7 +892,7 @@ const numeric &numeric::operator=(const char * s)
 
 
 /** 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");
@@ -885,7 +905,7 @@ const numeric numeric::inverse(void) const
  *  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;
@@ -910,7 +930,7 @@ int numeric::csgn(void) const
  *  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?
@@ -936,84 +956,86 @@ bool numeric::is_equal(const numeric &other) const
 
 
 /** 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);
 }
@@ -1033,7 +1055,7 @@ bool numeric::operator!=(const numeric &other) const
 
 /** 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;
@@ -1048,7 +1070,7 @@ bool numeric::is_cinteger(void) const
 
 /** 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;
@@ -1108,7 +1130,7 @@ bool numeric::operator>=(const numeric &other) const
 /** 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));
@@ -1118,7 +1140,7 @@ int numeric::to_int(void) const
 /** 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));
@@ -1127,7 +1149,7 @@ long numeric::to_long(void) const
 
 /** 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)));
@@ -1137,21 +1159,21 @@ double numeric::to_double(void) const
 /** 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)));
 }
@@ -1161,10 +1183,10 @@ const numeric numeric::imag(void) const
  *  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)));
@@ -1192,10 +1214,10 @@ const numeric numeric::numer(void) const
 /** 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)));
@@ -1223,9 +1245,9 @@ const numeric numeric::denom(void) const
  *
  *  @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;
@@ -1802,7 +1824,7 @@ const numeric irem(const numeric &a, const numeric &b)
 /** 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.
@@ -1918,21 +1940,21 @@ const numeric isqrt(const numeric &x)
 
 
 /** 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));
 }
index c56c56bd84dee5ae85715c7ca70ee0879d218ee3..33498f3a532b3e34da01be8c2179fa3ad0d59b00 100644 (file)
@@ -26,6 +26,8 @@
 #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; }
@@ -62,6 +64,17 @@ private:
        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
@@ -70,7 +83,7 @@ class numeric : public basic
        
 // member functions
        
-       // other ctors
+       // other constructors
 public:
        numeric(int i);
        numeric(unsigned int i);
@@ -83,7 +96,7 @@ public:
        // 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;
@@ -91,17 +104,19 @@ public:
        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)
@@ -124,38 +139,38 @@ public:
        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);
 
@@ -165,14 +180,12 @@ protected:
        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);
@@ -282,9 +295,9 @@ inline const numeric denom(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
index da3e766c366159bcc1a9c8c6034149292f8324c8..d588b98d995560a9f5c8850d7f5427fae685cdf1 100644 (file)
@@ -20,6 +20,9 @@
  *  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"
@@ -272,11 +275,77 @@ const relational operator>=(const ex & lh, const ex & rh)
        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;
 }
 
@@ -285,4 +354,71 @@ std::istream & operator>>(std::istream & is, ex & e)
        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
index 770d20862b39f1a4ab0980922cef8989effbc986..33e1c3e650275984cb7b671cddda05e29c501cdf 100644 (file)
@@ -85,6 +85,20 @@ const relational operator>=(const ex & lh, const ex & rh);
 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__
index 0730e3c8bf7fc385c5d4d1c1a97b6c565997cfab..0d24a04f950f312c54934ae5b8d2a0e994e7e117 100644 (file)
@@ -23,6 +23,7 @@
 #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"
@@ -46,22 +49,13 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(power, basic)
 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
@@ -70,7 +64,7 @@ DEFAULT_DESTROY(power)
 // 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);
@@ -225,14 +219,13 @@ bool power::info(unsigned inf) const
        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;
@@ -247,7 +240,7 @@ int power::degree(const ex & s) const
 {
        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
@@ -262,7 +255,7 @@ int power::ldegree(const ex & s) const
 {
        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
@@ -285,7 +278,7 @@ ex power::coeff(const ex & s, int n) const
                        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)
@@ -331,11 +324,11 @@ ex power::eval(int level) const
        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);
        }
@@ -426,11 +419,11 @@ ex power::eval(int level) const
                // ^(^(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())
@@ -439,13 +432,13 @@ ex power::eval(int level) const
                }
        
                // ^(*(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)) {
@@ -476,7 +469,7 @@ ex power::eval(int level) const
                // ^(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);
                }
        }
@@ -510,33 +503,47 @@ ex power::evalf(int level) const
        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
@@ -572,12 +579,12 @@ int power::compare_same_type(const basic & other) const
                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();
 }
@@ -591,7 +598,7 @@ ex power::expand(unsigned options) const
        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);
@@ -606,7 +613,7 @@ ex power::expand(unsigned options) const
                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));
@@ -618,7 +625,7 @@ ex power::expand(unsigned options) const
                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();
@@ -632,11 +639,11 @@ ex power::expand(unsigned options) const
        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
@@ -663,7 +670,7 @@ ex power::expand_add(const add & a, int n) const
        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
@@ -675,7 +682,7 @@ ex power::expand_add(const add & a, int n) const
        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;
@@ -693,7 +700,7 @@ ex power::expand_add(const add & a, int n) const
                                     !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]));
@@ -707,7 +714,7 @@ ex power::expand_add(const add & a, int n) const
                             !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]));
@@ -731,10 +738,10 @@ ex power::expand_add(const add & a, int n) const
                // 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];
        }
 
@@ -748,7 +755,7 @@ ex power::expand_add(const add & a, int n) const
 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();
 
@@ -766,8 +773,8 @@ ex power::expand_add_2(const add & a) const
                             !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 {
@@ -775,7 +782,7 @@ ex power::expand_add_2(const add & a) const
                                                     _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 {
@@ -783,7 +790,7 @@ ex power::expand_add_2(const add & a) const
                                                     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;
@@ -823,7 +830,7 @@ ex power::expand_mul(const mul & m, const numeric & n) const
        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()
index 46acef9773395f30cda05179af51fd0a88e97c4e..4e1df9fb87bc34d9fb0f5d245eaa72faf03e5e98 100644 (file)
@@ -41,7 +41,7 @@ class power : public basic
        
 // 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) {}
@@ -49,27 +49,28 @@ public:
        // 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
index 606e5e16cbc20ef30f5af8e4f82e535ad3779d64..1daede807571ce6add7fef1d438af4dde35f253b 100644 (file)
 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
index 007f1e404bece06710060bf222f57d0602ff1b47..8d4fc2f8612eeebe0367a2b4bf71bea454bd8bd9 100644 (file)
 
 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. */
@@ -46,7 +63,8 @@ class print_latex : public print_context
 {
 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. */
@@ -54,7 +72,8 @@ class print_python : public print_context
 {
 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. */
@@ -62,7 +81,8 @@ class print_python_repr : public print_context
 {
 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. */
@@ -70,7 +90,9 @@ class print_tree : public print_context
 {
 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 */
 };
 
@@ -79,7 +101,8 @@ class print_csrc : public print_context
 {
 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. */
@@ -87,7 +110,8 @@ class print_csrc_float : public print_csrc
 {
 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. */
@@ -95,7 +119,8 @@ class print_csrc_double : public print_csrc
 {
 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. */
@@ -103,7 +128,8 @@ class print_csrc_cl_N : public print_csrc
 {
 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. */
index bdf17d16c2b19f84dfd9ba2cebef81fb2f7ab874..e9887055f2e76b95c2d9a86d69e6d669d16c6347 100644 (file)
@@ -31,6 +31,7 @@
 #include "mul.h"
 #include "power.h"
 #include "relational.h"
+#include "operators.h"
 #include "symbol.h"
 #include "print.h"
 #include "archive.h"
@@ -42,21 +43,11 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(pseries, basic)
 
 
 /*
- *  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
@@ -84,7 +75,7 @@ pseries::pseries(const ex &rel_, const epvector &ops_) : basic(TINFO_pseries), s
  *  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;
@@ -125,8 +116,8 @@ void pseries::print(const print_context & c, unsigned level) const
                    << 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;
@@ -140,8 +131,8 @@ void pseries::print(const print_context & c, unsigned level) const
                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 << '(';
@@ -253,22 +244,18 @@ int pseries::compare_same_type(const basic & other) const
 }
 
 /** 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
@@ -409,13 +396,13 @@ ex pseries::evalf(int level) const
        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
@@ -423,10 +410,10 @@ ex pseries::subs(const lst & ls, const lst & lr, bool no_pattern) const
        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
@@ -499,7 +486,7 @@ ex pseries::convert_to_poly(bool no_order) const
        return e;
 }
 
-bool pseries::is_terminating(void) const
+bool pseries::is_terminating() const
 {
        return seq.empty() || !is_order_function((seq.end()-1)->rest);
 }
@@ -943,11 +930,10 @@ ex pseries::series(const relational & r, int order, unsigned options) const
  *  @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);
index 26c27306250a03a03177764962efc32734349cfc..17ed024dee7d157645c5d0d12209bbd2be903e2d 100644 (file)
@@ -36,17 +36,16 @@ class pseries : public basic
 {
        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;
@@ -54,7 +53,7 @@ public:
        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:
@@ -63,10 +62,10 @@ 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.
         *
@@ -78,11 +77,11 @@ public:
        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;
diff --git a/ginac/ptr.h b/ginac/ptr.h
new file mode 100644 (file)
index 0000000..1d1b49d
--- /dev/null
@@ -0,0 +1,147 @@
+/** @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__
index 34c9111884059f22ab49db86d73a7e14a6fa3fd1..7aee59464f4e4851c88811a9a76a5cb615c7b909 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <string>
+#include <map>
 #include <stdexcept>
 
 #include "registrar.h"
@@ -30,26 +31,41 @@ namespace GiNaC {
 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;
 }
 
index e620250ec7cc8537896d13db67c57e57bcb0c741..6969f0c23bb66cd5b27ccc7167125000edb0bdc3 100644 (file)
 #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. */
@@ -63,11 +66,18 @@ struct registered_class_info {
 #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
@@ -77,38 +87,25 @@ public: \
        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. */
index d779c632bd49e5bbf8b5bb236deb2b6980c74c01..c45dd1efc7b23683b00a5c493bf93a2da8ae7fa0 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdexcept>
 
 #include "relational.h"
+#include "operators.h"
 #include "numeric.h"
 #include "print.h"
 #include "archive.h"
@@ -34,23 +35,13 @@ namespace GiNaC {
 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
@@ -61,7 +52,7 @@ relational::relational(const ex & lhs, const ex & rhs, operators oper) : basic(T
 // 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)))
@@ -159,19 +150,23 @@ bool relational::info(unsigned inf) const
        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)
@@ -183,20 +178,20 @@ ex relational::eval(int level) const
        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
@@ -242,25 +237,25 @@ bool relational::match_same_type(const basic & other) const
        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:
@@ -281,12 +276,9 @@ unsigned relational::calchash(void) const
                        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);
@@ -301,13 +293,13 @@ unsigned relational::calchash(void) const
 //////////
 
 /** 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;    
 }
@@ -316,31 +308,36 @@ ex relational::rhs(void) const
 // 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"));
        }
index 9f58e0c7125e0a2aae73e50e4822d014181eddd3..591cc3b718486421006ed41cd051575641b04449 100644 (file)
@@ -45,36 +45,51 @@ public:
                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:
@@ -91,6 +106,12 @@ template<> inline bool is_exactly_a<relational>(const basic & obj)
        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__
index cdd346f74e0e1b18e32fe83e608c2c089039493f..4218a6ea917a1002973838d9f60d032479c25ea4 100644 (file)
@@ -44,8 +44,8 @@ bool remember_table_entry::is_equal(function const & f) const
 {
        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;
@@ -168,20 +168,20 @@ void remember_table::add_entry(function const & f, ex const & result)
        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;
index 704c3f8ef7c7a0c060fb45a43ce21a9ec8ec647b..868b96620967871d507aca9c6501d82e08589a2c 100644 (file)
@@ -41,9 +41,9 @@ class remember_table_entry {
 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;
@@ -86,11 +86,11 @@ public:
        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;
index d2f6a9b8ddbe22380b6a07a407cc68b4bddda94e..9c79333a0b0e15ad2f8350a11bc2e07cf04cb690 100644 (file)
@@ -1,6 +1,6 @@
 /** @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
index 9bfb97ce3f50e3c216c90ab9ba2f58b4605a7eb2..23ae93c0940a6de0e98dc0864a46af4604b4eca1 100644 (file)
@@ -1,6 +1,6 @@
 /** @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__
diff --git a/ginac/structure.pl b/ginac/structure.pl
deleted file mode 100755 (executable)
index 5ec55af..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-#!/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";
index 48579ccf65ae658fc571413cf9a22f6f711069c8..6b265a775e74e67b4d6877618620cf1a187ce4ed 100644 (file)
@@ -35,56 +35,30 @@ namespace GiNaC {
 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);
 }
 
@@ -93,27 +67,29 @@ symbol::symbol(const std::string & initname, const std::string & texname) : inhe
 //////////
 
 /** 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;
 }
 
@@ -211,12 +187,9 @@ bool symbol::is_equal_same_type(const basic & other) const
        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;
 }
@@ -235,15 +208,15 @@ unsigned symbol::calchash(void) const
 
 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);
@@ -253,14 +226,14 @@ void symbol::unassign(void)
 
 /** 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"
@@ -294,7 +267,7 @@ unsigned symbol::next_serial = 0;
 //////////
 
 /** 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)
 {
 }
 
index 5dc869db03f7e1cd91ba9fce88f2be13b8a36a73..8ff63130d0f6532472b4af75760d9db2a934d051 100644 (file)
@@ -26,6 +26,7 @@
 #include <string>
 #include "basic.h"
 #include "ex.h"
+#include "ptr.h"
 
 namespace GiNaC {
 
@@ -38,21 +39,23 @@ 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);
@@ -64,30 +67,32 @@ public:
        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;
 };
index 536d1cd5115c31edf125ce83693afdd4792dd667..a0a2af1dbdba3d7ae9b2960819a1b85ea56cfd16 100644 (file)
@@ -27,6 +27,7 @@
 #include "symmetry.h"
 #include "lst.h"
 #include "numeric.h" // for factorial()
+#include "operators.h"
 #include "print.h"
 #include "archive.h"
 #include "utils.h"
@@ -50,7 +51,7 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(symmetry, basic)
 */
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
 //////////
 
 symmetry::symmetry() : type(none)
@@ -58,16 +59,6 @@ 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
 //////////
@@ -89,7 +80,7 @@ symmetry::symmetry(symmetry_type t, const symmetry &c1, const symmetry &c2) : ty
 //////////
 
 /** 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)))
@@ -204,8 +195,8 @@ void symmetry::print(const print_context & c, unsigned level) const
                                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 << ",";
@@ -356,10 +347,8 @@ static ex symm(const ex & e, exvector::const_iterator first, exvector::const_ite
        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;
@@ -405,10 +394,8 @@ ex symmetrize_cyclic(const ex & e, exvector::const_iterator first, exvector::con
        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
@@ -425,20 +412,14 @@ ex symmetrize_cyclic(const ex & e, exvector::const_iterator first, exvector::con
 /** 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);
 }
 
@@ -446,10 +427,7 @@ ex ex::antisymmetrize(const lst & l) const
  *  (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());
 }
 
index 4ef1cd0db93a9f1f4b64374f6c59bfd06f55bf27..0b805edc08c794a607b965e93e7bb95f3e55fab1 100644 (file)
@@ -83,7 +83,7 @@ public:
        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:
@@ -100,22 +100,22 @@ 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); }
index 48393665ad5fc0555add8a19bba463af14abf288..d78eff6604078ebf1b913e63d4682bba54c7c20f 100644 (file)
@@ -29,6 +29,7 @@
 #include "indexed.h"
 #include "symmetry.h"
 #include "relational.h"
+#include "operators.h"
 #include "lst.h"
 #include "numeric.h"
 #include "matrix.h"
@@ -46,16 +47,16 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(spinmetric, tensmetric)
 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)
 {
@@ -72,12 +73,6 @@ minkmetric::minkmetric(bool ps) : pos_sig(ps)
        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;
@@ -88,13 +83,6 @@ tensepsilon::tensepsilon(bool mink, bool ps) : minkowski(mink), pos_sig(ps)
        tinfo_key = TINFO_tensepsilon;
 }
 
-void tensepsilon::copy(const tensepsilon & other)
-{
-       inherited::copy(other);
-       minkowski = other.minkowski;
-       pos_sig = other.pos_sig;
-}
-
 //////////
 // archiving
 //////////
@@ -106,7 +94,7 @@ DEFAULT_ARCHIVING(spinmetric)
 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);
 }
@@ -117,7 +105,7 @@ void minkmetric::archive(archive_node &n) const
        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);
@@ -312,15 +300,15 @@ ex tensepsilon::eval_indexed(const basic & i) const
                // 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())
@@ -346,7 +334,7 @@ bool tensor::replace_contr_index(exvector::iterator self, exvector::iterator oth
 
 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)) {
 
@@ -400,11 +388,11 @@ bool tensmetric::contract_with(exvector::iterator self, exvector::iterator other
 
        // 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);
 }
 
@@ -417,7 +405,7 @@ bool spinmetric::contract_with(exvector::iterator self, exvector::iterator 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));
@@ -450,7 +438,7 @@ bool spinmetric::contract_with(exvector::iterator self, exvector::iterator other
 
        // 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
@@ -461,7 +449,7 @@ bool spinmetric::contract_with(exvector::iterator self, exvector::iterator other
 
 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)) {
 
@@ -494,15 +482,15 @@ bool tensepsilon::contract_with(exvector::iterator self, exvector::iterator othe
        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)
@@ -526,7 +514,7 @@ bool tensepsilon::contract_with(exvector::iterator self, exvector::iterator othe
 
 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);
@@ -534,7 +522,7 @@ ex delta_tensor(const ex & i1, const ex & 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);
@@ -542,7 +530,7 @@ ex metric_tensor(const ex & i1, const ex & 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);
@@ -550,7 +538,7 @@ ex lorentz_g(const ex & i1, const ex & i2, bool pos_sig)
 
 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"));
@@ -560,7 +548,7 @@ ex spinor_metric(const ex & i1, const ex & i2)
 
 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();
@@ -574,7 +562,7 @@ ex epsilon_tensor(const ex & i1, const ex & i2)
 
 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();
@@ -588,7 +576,7 @@ ex epsilon_tensor(const ex & i1, const ex & i2, const ex & i3)
 
 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();
index a9cc67ed1f3bd8651e59619f44b4c554b73186b2..712ec7e131539ce8aaf3c92e815f52486521d1a0 100644 (file)
@@ -41,7 +41,7 @@ protected:
 
        // 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:
@@ -140,7 +140,7 @@ 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. */
 };
 
 
index 3d9e794f1c19eaac328482f0c929b34c01b69b23..12a8d1b3251db17dcc19a23fba05c5fd6a311c4b 100644 (file)
@@ -39,7 +39,7 @@ pole_error::pole_error(const std::string& what_arg, int degree)
        : 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;
 }
@@ -187,6 +187,7 @@ const ex _ex_1_4= _num_1_4;
 
 // static numeric 0
 const numeric *_num0_p;
+const basic *_num0_bp;
 const numeric &_num0 = *_num0_p;
 const ex _ex0 = _num0;
 
@@ -340,6 +341,7 @@ library_init::library_init()
                _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)));
@@ -384,10 +386,10 @@ library_init::~library_init()
 
 // 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
@@ -408,14 +410,14 @@ library_init::~library_init()
 
 
 //////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor, destructor, copy constructor and assignment operator
 //////////
 
 // public
 // protected
 
 //////////
-// other ctors
+// other constructors
 //////////
 
 // public
index 1d24a82d7791f9c81c649a5643e489f678bd0724..0af6707afbb85c4a911d7404c58a0f4426e23dc4 100644 (file)
 #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);
@@ -56,55 +44,46 @@ 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
 }
 
@@ -304,7 +283,6 @@ again:
 // the library but should not be used outside it since it is
 // potentially confusing.
 
-class numeric;
 class ex;
 
 extern const numeric *_num_120_p;
@@ -380,6 +358,7 @@ extern const numeric *_num_1_4_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;
@@ -458,32 +437,17 @@ extern const ex _ex120;
 
 // 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 \
 { \
@@ -517,21 +481,6 @@ void classname::print(const print_context & c, unsigned level) 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
 
 
index c389c98f1452b9a94b90368a249bb26507c70117..97fab9e919e101895a52d13d7cb9058886236906 100644 (file)
@@ -32,38 +32,31 @@ 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
@@ -101,7 +94,7 @@ void wildcard::print(const print_context & c, unsigned level) const
                c.s << "$" << label;
 }
 
-unsigned wildcard::calchash(void) const
+unsigned wildcard::calchash() const
 {
        // this is where the schoolbook method
        // (golden_ratio_hash(tinfo()) ^ label)
index 78c541b572f5b64a66763166f8f2f04d3e2e451c..86c5f4a13671579e8a403dd348445009e5381ceb 100644 (file)
@@ -45,11 +45,11 @@ public:
        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:
index 3c6f0dfb723aa11db52823bb244e33b985bd53ac..973d8951c5b0992fd47c0fce069ccd7e1203e1c2 100644 (file)
@@ -87,9 +87,6 @@ score                 return T_SCORE;
 ">="                   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;
index 24abefb8ea779dc8fc4524eff0123823f23ab924..723cfccd2e1b70a72321881baa47605db510656e 100644 (file)
@@ -50,7 +50,7 @@ static char *orig_basic_word_break_characters;
 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];
 
@@ -356,9 +356,9 @@ static ex f_determinant(const exprseq &e)
 
 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;
 }