]> www.ginac.de Git - ginac.git/commitdiff
- switched to automake build environment
authorChristian Bauer <Christian.Bauer@uni-mainz.de>
Tue, 9 Nov 1999 22:56:40 +0000 (22:56 +0000)
committerChristian Bauer <Christian.Bauer@uni-mainz.de>
Tue, 9 Nov 1999 22:56:40 +0000 (22:56 +0000)
121 files changed:
AUTHORS [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
Makefile.in
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
acinclude.m4 [new file with mode: 0644]
aclocal.m4
check/Makefile.am [new file with mode: 0644]
check/Makefile.in
check/check.h
check/differentiation.cpp
check/expand_subs.cpp
check/inifcns_consist.cpp
check/lsolve_onedim.cpp
check/main.cpp
check/matrix_checks.cpp
check/normalization.cpp
check/numeric_consist.cpp
check/numeric_output.cpp
check/paranoia_check.cpp
check/poly_gcd.cpp
check/powerlaws.cpp
check/run_checks [new file with mode: 0755]
check/series_expansion.cpp
config.guess [new file with mode: 0755]
config.h.in
config.sub [new file with mode: 0755]
configure
configure.in
doc/Makefile [deleted file]
doc/Makefile.am [new file with mode: 0644]
doc/Makefile.in
ginac/Makefile.am [new file with mode: 0644]
ginac/Makefile.in [new file with mode: 0644]
ginac/add.cpp [new file with mode: 0644]
ginac/add.h [new file with mode: 0644]
ginac/basic.cpp [new file with mode: 0644]
ginac/basic.h [new file with mode: 0644]
ginac/clifford.cpp [new file with mode: 0644]
ginac/clifford.h [new file with mode: 0644]
ginac/color.cpp [new file with mode: 0644]
ginac/color.h [new file with mode: 0644]
ginac/coloridx.cpp [new file with mode: 0644]
ginac/coloridx.h [new file with mode: 0644]
ginac/constant.cpp [new file with mode: 0644]
ginac/constant.h [new file with mode: 0644]
ginac/container.pl [new file with mode: 0755]
ginac/debugmsg.h [new file with mode: 0644]
ginac/diff.cpp [new file with mode: 0644]
ginac/ex.cpp [new file with mode: 0644]
ginac/ex.h [new file with mode: 0644]
ginac/expair.h [new file with mode: 0644]
ginac/expairseq.cpp [new file with mode: 0644]
ginac/expairseq.h [new file with mode: 0644]
ginac/exprseq.cpp [new file with mode: 0644]
ginac/exprseq.h [new file with mode: 0644]
ginac/exprseq_suppl.cpp [new file with mode: 0644]
ginac/fail.cpp [new file with mode: 0644]
ginac/fail.h [new file with mode: 0644]
ginac/flags.h [new file with mode: 0644]
ginac/function.cpp [new file with mode: 0644]
ginac/function.h [new file with mode: 0644]
ginac/function.pl [new file with mode: 0755]
ginac/ginac.h [new file with mode: 0644]
ginac/idx.cpp [new file with mode: 0644]
ginac/idx.h [new file with mode: 0644]
ginac/indexed.cpp [new file with mode: 0644]
ginac/indexed.h [new file with mode: 0644]
ginac/inifcns.cpp [new file with mode: 0644]
ginac/inifcns.h [new file with mode: 0644]
ginac/inifcns_gamma.cpp [new file with mode: 0644]
ginac/inifcns_trans.cpp [new file with mode: 0644]
ginac/isospin.cpp [new file with mode: 0644]
ginac/isospin.h [new file with mode: 0644]
ginac/lorentzidx.cpp [new file with mode: 0644]
ginac/lorentzidx.h [new file with mode: 0644]
ginac/lst.cpp [new file with mode: 0644]
ginac/lst.h [new file with mode: 0644]
ginac/lst_suppl.cpp [new file with mode: 0644]
ginac/matrix.cpp [new file with mode: 0644]
ginac/matrix.h [new file with mode: 0644]
ginac/mul.cpp [new file with mode: 0644]
ginac/mul.h [new file with mode: 0644]
ginac/ncmul.cpp [new file with mode: 0644]
ginac/ncmul.h [new file with mode: 0644]
ginac/normal.cpp [new file with mode: 0644]
ginac/normal.h [new file with mode: 0644]
ginac/numeric.cpp [new file with mode: 0644]
ginac/numeric.h [new file with mode: 0644]
ginac/operators.cpp [new file with mode: 0644]
ginac/operators.h [new file with mode: 0644]
ginac/power.cpp [new file with mode: 0644]
ginac/power.h [new file with mode: 0644]
ginac/print.cpp [new file with mode: 0644]
ginac/printcsrc.cpp [new file with mode: 0644]
ginac/printraw.cpp [new file with mode: 0644]
ginac/printtree.cpp [new file with mode: 0644]
ginac/relational.cpp [new file with mode: 0644]
ginac/relational.h [new file with mode: 0644]
ginac/series.cpp [new file with mode: 0644]
ginac/series.h [new file with mode: 0644]
ginac/simp_lor.cpp [new file with mode: 0644]
ginac/simp_lor.h [new file with mode: 0644]
ginac/structure.cpp [new file with mode: 0644]
ginac/structure.h [new file with mode: 0644]
ginac/structure.pl [new file with mode: 0755]
ginac/symbol.cpp [new file with mode: 0644]
ginac/symbol.h [new file with mode: 0644]
ginac/tinfos.h [new file with mode: 0644]
ginac/utils.cpp [new file with mode: 0644]
ginac/utils.h [new file with mode: 0644]
ginsh/Makefile.am [new file with mode: 0644]
ginsh/Makefile.in
ginsh/ginsh.h
ginsh/ginsh_lexer.ll [moved from ginsh/ginsh.l with 96% similarity]
ginsh/ginsh_parser.yy [moved from ginsh/ginsh.y with 99% similarity]
ginsh/strdup.c [new file with mode: 0644]
ltconfig [new file with mode: 0755]
ltmain.sh [new file with mode: 0644]
stamp-h.in [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..2f5ce75
--- /dev/null
@@ -0,0 +1,2 @@
+## Process this file with automake to produce Makefile.in
+SUBDIRS = ginac check ginsh doc
index bcf90630266e21fb135fec79b0a2f761878a668d..b3e55f262462c356e8bc9562419e2a968c95d0f2 100644 (file)
-# This is the prototype Makefile for the GiNaC package. 
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
 
-# Not every make knows what CXX is, so we inherit it together with some other
-# values from configure which checks it anyways:
-CXX = @CXX@
-CXXFLAGS = @CXXFLAGS@
-CPPFLAGS = @CPPFLAGS@
-DEFS = @DEFS@
-LIBS = @LIBS@
-LDFLAGS = @LDFLAGS@
 
-# Here come the usual install directories in GNU-configure fashion:
+SHELL = /bin/sh
+
 srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
 prefix = @prefix@
 exec_prefix = @exec_prefix@
+
 bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
 libdir = @libdir@
-includedir = @includedir@/GiNaC
-
-# This must be empty unless the user has called configure with --enable-shared:
-shared = @shared@
-
-# The version-number is tracked in configure.in only:
-LIBGINACVER = @LibGiNaC_Ver@
-
-# Autoconf macro AC_PROC_INSTALL sets these:
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-
-
-all:   lib ginsh/ginsh
-       echo "now type make install"
-
-src/libginac.la:
-       cd src; ${MAKE} libginac.la
-
-src/.libs/libginac.a:
-       cd src; ${MAKE} .libs/libginac.a
-
-lib:
-       cd src; ${MAKE} all
-
-
-# Targets for making the GiNaC interactive shell (ginsh)
-ginsh: ginsh/ginsh
-
-ginsh/ginsh:
-       if [ "${shared}" ]; then \
-               ${MAKE} sharedginsh; \
-       else \
-               ${MAKE} staticginsh; \
-       fi
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
 
-sharedginsh: src/libginac.la
-       cd ginsh; ${MAKE} sharedginsh
+DISTDIR =
 
-staticginsh: src/.libs/libginac.a
-       cd ginsh; ${MAKE} staticginsh
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
 
+top_builddir = .
 
-# Target for running a test-suite across the library:
-check:
-       if [ "${shared}" ]; then \
-               ${MAKE} sharedcheck; \
-       else \
-               ${MAKE} staticcheck; \
-       fi
-
-sharedcheck: src/libginac.la
-       cd check; ${MAKE} sharedcheck
-
-staticcheck: src/.libs/libginac.a
-       cd check; ${MAKE} staticcheck
-
-
-# Targets for installation in install directories.  The user-visible target
-# `install' determines which one to call (static lib only or both shared and
-# static lib).
-install: installdirs
-       @ if [ "${shared}" ]; then \
-               ${MAKE} sharedinst; \
-       else \
-               ${MAKE} staticinst; \
-       fi
-       ${INSTALL_DATA} include/GiNaC/*.h ${includedir}/
-       cd ginsh; ${MAKE} install
-       cd doc; ${MAKE} install
-
-sharedinst: src/libginac.la
-       ${LIBTOOL} install src/libginac.la ${libdir}/libginac.la
-       ${LIBTOOL} -n --finish ${libdir}
-
-staticinst: src/.libs/libginac.a
-       ${INSTALL_DATA} src/.libs/libginac.a ${libdir}/libginac.a
-
-installdirs:
-       ./mkinstalldirs ${libdir} ${includedir}
-
-
-# Targets for cleaning up. (clean deletes files created by built, distclean
-# deletes files created by configuration, uninstall removes all files related
-# to GiNaC from the system.)
-clean:
-       cd src; ${MAKE} clean
-       cd check; ${MAKE} clean
-       cd ginsh; ${MAKE} clean
-
-distclean: clean
-       cd src; ${MAKE} distclean
-       cd check; ${MAKE} distclean
-       cd ginsh; ${MAKE} distclean
-       rm -f config.status config.log config.cache config.h Makefile
-
-uninstall:
-       rm -f ${libdir}/libginac.*
-       rm -rf ${includedir}
-       cd ginsh; ${MAKE} uninstall
-       cd doc; ${MAKE} uninstall
-
-
-# Convenient targets for those who wish to extend on the documentation:
-doc:
-       cd doc; ${MAKE} all
-reference:
-       cd doc; ${MAKE} reference
-tutorial:
-       cd doc; ${MAKE} tutorial
-
-
-# Special dummy targets:
-.PHONY: clean distclean all install installdirs uninstall check ginsh doc
-.SUFFIXES: .o .lo .cpp
-.SILENT: all check sharedcheck staticcheck doc reference tutorial
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
 
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CC = @CC@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+DOXYGEN = @DOXYGEN@
+DVIPS = @DVIPS@
+FIG2DEV = @FIG2DEV@
+JADE = @JADE@
+JADETEX = @JADETEX@
+LATEX = @LATEX@
+LD = @LD@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINDEX = @MAKEINDEX@
+MAKEINFO = @MAKEINFO@
+NM = @NM@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+
+SUBDIRS = ginac check ginsh doc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  README AUTHORS COPYING ChangeLog INSTALL Makefile.am \
+Makefile.in NEWS acconfig.h acinclude.m4 aclocal.m4 config.guess \
+config.h.in config.sub configure configure.in install-sh ltconfig \
+ltmain.sh missing mkinstalldirs stamp-h.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: all-recursive-am all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4): @MAINT@ configure.in  acinclude.m4
+       cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure
+       $(SHELL) ./config.status --recheck
+$(srcdir)/configure: @MAINT@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+       cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+       @:
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES= CONFIG_HEADERS=config.h \
+            $(SHELL) ./config.status
+       @echo timestamp > stamp-h
+$(srcdir)/config.h.in: @MAINT@$(srcdir)/stamp-h.in
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
+       cd $(top_srcdir) && $(AUTOHEADER)
+       @echo timestamp > $(srcdir)/stamp-h.in
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+       -rm -f config.h
+
+maintainer-clean-hdr:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+       @set fnord $(MAKEFLAGS); amf=$$2; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         target=`echo $@ | sed s/-recursive//`; \
+         echo "Making $$target in $$subdir"; \
+         (cd $$subdir && $(MAKE) $$target) \
+          || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+       done && test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+       @set fnord $(MAKEFLAGS); amf=$$2; \
+       rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+         rev="$$subdir $$rev"; \
+       done; \
+       for subdir in $$rev; do \
+         target=`echo $@ | sed s/-recursive//`; \
+         echo "Making $$target in $$subdir"; \
+         (cd $$subdir && $(MAKE) $$target) \
+          || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         (cd $$subdir && $(MAKE) tags); \
+       done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+       done; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+       -rm -rf $(distdir)
+       GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz
+       mkdir $(distdir)/=build
+       mkdir $(distdir)/=inst
+       dc_install_base=`cd $(distdir)/=inst && pwd`; \
+       cd $(distdir)/=build \
+         && ../configure --srcdir=.. --prefix=$$dc_install_base \
+         && $(MAKE) \
+         && $(MAKE) dvi \
+         && $(MAKE) check \
+         && $(MAKE) install \
+         && $(MAKE) installcheck \
+         && $(MAKE) dist
+       -rm -rf $(distdir)
+       @echo "========================"; \
+       echo "$(distdir).tar.gz is ready for distribution"; \
+       echo "========================"
+dist: distdir
+       -chmod -R a+r $(distdir)
+       GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
+       -rm -rf $(distdir)
+dist-all: distdir
+       -chmod -R a+r $(distdir)
+       GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
+       -rm -rf $(distdir)
+distdir: $(DISTFILES)
+       -rm -rf $(distdir)
+       mkdir $(distdir)
+       -chmod 777 $(distdir)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+       for subdir in $(SUBDIRS); do \
+         test -d $(distdir)/$$subdir \
+         || mkdir $(distdir)/$$subdir \
+         || exit 1; \
+         chmod 777 $(distdir)/$$subdir; \
+         (cd $$subdir && $(MAKE) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+           || exit 1; \
+       done
+info: info-recursive
+dvi: dvi-recursive
+check: all-am
+       $(MAKE) check-recursive
+installcheck: installcheck-recursive
+all-recursive-am: config.h
+       $(MAKE) all-recursive
+
+all-am: Makefile config.h
+
+install-exec: install-exec-recursive
+       @$(NORMAL_INSTALL)
+
+install-data: install-data-recursive
+       @$(NORMAL_INSTALL)
+
+install: install-recursive
+       @:
+
+uninstall: uninstall-recursive
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs: installdirs-recursive
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean-am:  mostlyclean-hdr mostlyclean-tags mostlyclean-generic
+
+clean-am:  clean-hdr clean-tags clean-generic mostlyclean-am
+
+distclean-am:  distclean-hdr distclean-tags distclean-generic clean-am
+
+maintainer-clean-am:  maintainer-clean-hdr maintainer-clean-tags \
+               maintainer-clean-generic distclean-am
+
+mostlyclean:  mostlyclean-recursive mostlyclean-am
+
+clean:  clean-recursive clean-am
+
+distclean:  distclean-recursive distclean-am
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-recursive maintainer-clean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       -rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+install-data-recursive uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info dvi \
+installcheck all-recursive-am all-am install-exec install-data install \
+uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644 (file)
index 0000000..fff1839
--- /dev/null
@@ -0,0 +1,116 @@
+dnl ===========================================================================
+dnl Additional macros used to configure GiNaC.  We don't start additions' names
+dnl with AC_ but with GINAC_ in order to avoid future trouble.
+dnl ===========================================================================
+
+dnl Generally, it is a bad idea to put specialized header files for a library
+dnl into a generic directory like /usr/local/include/.  Instead, one should put
+dnl them into a subdirectory.  GiNaC does it, NTL does it.  Unfortunately, CLN
+dnl doesn't do so but some people choose to do it by hand.  In these cases we
+dnl need to #include <CLN/cln.h>, otherwise #include <cln.h>.  This macro
+dnl tries to be clever and find out the correct way by defining the variable
+dnl HAVE_CLN_CLN_H in config.h:
+AC_DEFUN(GINAC_CHECK_CLN_H,
+    [AC_PROVIDE([$0])
+    AC_CHECK_HEADERS(CLN/cln.h, ,
+        AC_CHECK_HEADERS(cln.h, ,
+            AC_MSG_ERROR([cannot find header for Bruno Haible's CLN]);
+        )
+    )
+])
+
+dnl This macro is needed because the generic AC_CHECK_LIB doesn't work because
+dnl C++ is more strongly typed than C.  Therefore we need to work with the 
+dnl more fundamental AC_TRY_LINK instead.
+AC_DEFUN(GINAC_CHECK_LIBCLN,
+    [AC_PROVIDE([$0])
+    AC_MSG_CHECKING([how to link with libcln])
+    saved_LIBS="${LIBS}"
+    AC_CACHE_VAL(ginac_cv_lib_cln_link,
+        [LIBS="-lcln"
+        case "${ac_cv_header_CLN_cln_h}" in
+        "yes")
+            AC_TRY_LINK([#include <CLN/cln.h>],
+                [factorial(1);],
+                ginac_cv_lib_cln_link="-lcln",
+                ginac_cv_lib_cln_link="fail")
+            ;;
+        *)
+            AC_TRY_LINK([#include <cln.h>],
+                [factorial(1);],
+                ginac_cv_lib_cln_link="-lcln",
+                ginac_cv_lib_cln_link="fail")
+            ;;
+        esac
+    ])
+    case "${ginac_cv_lib_cln_link}" in
+dnl linking worked:
+    "-lcln")
+        LIBS="-lcln ${saved_LIBS}"
+        AC_MSG_RESULT([-lcln])
+        GINAC_CHECK_LIBCLN_SANITY
+    ;;
+dnl linking failed:
+    "fail")
+        LIBS="${saved_LIBS}"
+        AC_MSG_RESULT([])
+        AC_MSG_WARN([linking with libcln failed])
+    ;;
+dnl should never ever get here:
+    *)
+        LIBS="${saved_LIBS}"
+    ;;
+    esac
+])
+
+dnl Check if the CLN library suits our needs, i.e. if it is new enough, by
+dnl trying to run into a little bug which was present till version 1.0.1 and
+dnl then removed.
+AC_DEFUN(GINAC_CHECK_LIBCLN_SANITY,
+    [AC_PROVIDE([$0])
+    AC_MSG_CHECKING([whether libcln behaves sane])
+    AC_CACHE_VAL(ginac_cv_lib_cln_integrity,
+        [
+        case "${ac_cv_header_CLN_cln_h}" in
+        "yes")
+            AC_TRY_RUN([#include <CLN/cln.h>
+int main() {
+cl_RA q(3); q = q/2; cl_RA p(3); p = p/2;
+if (q+p != 3) return 1; else return 0;
+}],
+                ginac_cv_lib_cln_integrity="sane",
+                ginac_cv_lib_cln_integrity="insane",
+                ginac_cv_lib_cln_integrity="guessing sane")
+            ;;
+        *)
+            AC_TRY_RUN([#include <cln.h>
+int main() {
+cl_RA q(3); q = q/2; cl_RA p(3); p = p/2;
+if (q+p != 3) return 1; else return 0;
+}],
+                ginac_cv_lib_cln_integrity="sane",
+                ginac_cv_lib_cln_integrity="insane",
+                ginac_cv_lib_cln_integrity="guessing sane")
+            ;;
+        esac
+    ])
+    case "${ginac_cv_lib_cln_integrity}" in
+dnl exit status was 0:
+    "sane")
+        AC_MSG_RESULT([yes])
+    ;;
+dnl exit status was not 0:
+    "insane")
+        AC_MSG_RESULT([no])
+        AC_MSG_WARN([maybe version of libcln is older than 1.0.2?])
+    ;;
+dnl test-program was not run because we are cross-compiling:
+    "guessing sane")
+        AC_MSG_RESULT([hopefully])
+    ;;
+dnl should never ever get here:
+    *)
+        AC_MSG_WARN([you found a bug in the configure script!])
+    ;;
+    esac
+])
index fff1839960e1339404df8b26a49cff0eac98a519..289b92e74df69f63b32be6022c1e9b108473d538 100644 (file)
@@ -1,3 +1,15 @@
+dnl aclocal.m4 generated automatically by aclocal 1.3
+
+dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+dnl This Makefile.in is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
 dnl ===========================================================================
 dnl Additional macros used to configure GiNaC.  We don't start additions' names
 dnl with AC_ but with GINAC_ in order to avoid future trouble.
@@ -114,3 +126,398 @@ dnl should never ever get here:
     ;;
     esac
 ])
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN(AM_CONFIG_HEADER,
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated.  We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<<am_indx=1
+for am_file in <<$1>>; do
+  case " <<$>>CONFIG_HEADERS " in
+  *" <<$>>am_file "*<<)>>
+    echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+    ;;
+  esac
+  am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AM_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION"))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+
+# serial 1
+
+AC_DEFUN(AM_PROG_INSTALL,
+[AC_REQUIRE([AC_PROG_INSTALL])
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+# Add --enable-maintainer-mode option to configure.
+# From Jim Meyering
+
+# serial 1
+
+AC_DEFUN(AM_MAINTAINER_MODE,
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+  dnl maintainer-mode is disabled by default
+  AC_ARG_ENABLE(maintainer-mode,
+[  --enable-maintainer-mode enable make rules and dependencies not useful
+                          (and sometimes confusing) to the casual installer],
+      USE_MAINTAINER_MODE=$enableval,
+      USE_MAINTAINER_MODE=no)
+  AC_MSG_RESULT($USE_MAINTAINER_MODE)
+  if test $USE_MAINTAINER_MODE = yes; then
+    MAINT=
+  else
+    MAINT='#M#'
+  fi
+  AC_SUBST(MAINT)dnl
+]
+)
+
+
+# serial 24 AM_PROG_LIBTOOL
+AC_DEFUN(AM_PROG_LIBTOOL,
+[AC_REQUIRE([AM_ENABLE_SHARED])dnl
+AC_REQUIRE([AM_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_RANLIB])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AM_PROG_LD])dnl
+AC_REQUIRE([AM_PROG_NM])dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+dnl
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Check for any special flags to pass to ltconfig.
+libtool_flags=
+test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
+test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
+test "$silent" = yes && libtool_flags="$libtool_flags --silent"
+test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
+test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case "$host" in
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  CFLAGS="$CFLAGS -belf"
+  ;;
+esac
+
+# Actually configure libtool.  ac_aux_dir is where install-sh is found.
+CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
+LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \
+$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \
+|| AC_MSG_ERROR([libtool configure failed])
+])
+
+# AM_ENABLE_SHARED - implement the --enable-shared flag
+# Usage: AM_ENABLE_SHARED[(DEFAULT)]
+#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
+#   `yes'.
+AC_DEFUN(AM_ENABLE_SHARED,
+[define([AM_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(shared,
+changequote(<<, >>)dnl
+<<  --enable-shared         build shared libraries [default=>>AM_ENABLE_SHARED_DEFAULT]
+changequote([, ])dnl
+[  --enable-shared=PKGS    only build shared libraries if the current package
+                          appears as an element in the PKGS list],
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+  enable_shared=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_shared=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac],
+enable_shared=AM_ENABLE_SHARED_DEFAULT)dnl
+])
+
+# AM_DISABLE_SHARED - set the default shared flag to --disable-shared
+AC_DEFUN(AM_DISABLE_SHARED,
+[AM_ENABLE_SHARED(no)])
+
+# AM_DISABLE_STATIC - set the default static flag to --disable-static
+AC_DEFUN(AM_DISABLE_STATIC,
+[AM_ENABLE_STATIC(no)])
+
+# AM_ENABLE_STATIC - implement the --enable-static flag
+# Usage: AM_ENABLE_STATIC[(DEFAULT)]
+#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
+#   `yes'.
+AC_DEFUN(AM_ENABLE_STATIC,
+[define([AM_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(static,
+changequote(<<, >>)dnl
+<<  --enable-static         build static libraries [default=>>AM_ENABLE_STATIC_DEFAULT]
+changequote([, ])dnl
+[  --enable-static=PKGS    only build shared libraries if the current package
+                          appears as an element in the PKGS list],
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+  enable_static=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_static=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac],
+enable_static=AM_ENABLE_STATIC_DEFAULT)dnl
+])
+
+
+# AM_PROG_LD - find the path to the GNU or non-GNU linker
+AC_DEFUN(AM_PROG_LD,
+[AC_ARG_WITH(gnu-ld,
+[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])
+ac_prog=ld
+if test "$ac_cv_prog_gcc" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by GCC])
+  ac_prog=`($CC -print-prog-name=ld) 2>&5`
+  case "$ac_prog" in
+  # Accept absolute paths.
+  /* | [A-Za-z]:\\*)
+    test -z "$LD" && LD="$ac_prog"
+    ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(ac_cv_path_LD,
+[if test -z "$LD"; then
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog"; then
+      ac_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+       test "$with_gnu_ld" != no && break
+      else
+        test "$with_gnu_ld" != yes && break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  ac_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$ac_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_SUBST(LD)
+AM_PROG_LD_GNU
+])
+
+AC_DEFUN(AM_PROG_LD_GNU,
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+  ac_cv_prog_gnu_ld=yes
+else
+  ac_cv_prog_gnu_ld=no
+fi])
+])
+
+# AM_PROG_NM - find the path to a BSD-compatible name lister
+AC_DEFUN(AM_PROG_NM,
+[AC_MSG_CHECKING([for BSD-compatible nm])
+AC_CACHE_VAL(ac_cv_path_NM,
+[case "$NM" in
+/* | [A-Za-z]:\\*)
+  ac_cv_path_NM="$NM" # Let the user override the test with a path.
+  ;;
+*)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/nm; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -B"
+      elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -p"
+      else
+        ac_cv_path_NM="$ac_dir/nm"
+      fi
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
+  ;;
+esac])
+NM="$ac_cv_path_NM"
+AC_MSG_RESULT([$NM])
+AC_SUBST(NM)
+])
+
+
+dnl AM_PROG_LEX
+dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT
+AC_DEFUN(AM_PROG_LEX,
+[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1)
+AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex")
+AC_PROG_LEX
+AC_DECL_YYTEXT])
+
diff --git a/check/Makefile.am b/check/Makefile.am
new file mode 100644 (file)
index 0000000..36d5f97
--- /dev/null
@@ -0,0 +1,8 @@
+## Process this file with automake to produce Makefile.in
+noinst_PROGRAMS = check_ginac
+check_ginac_SOURCES = paranoia_check.cpp numeric_output.cpp numeric_consist.cpp \
+  powerlaws.cpp expand_subs.cpp inifcns_consist.cpp differentiation.cpp \
+  poly_gcd.cpp normalization.cpp lsolve_onedim.cpp matrix_checks.cpp \
+  series_expansion.cpp fcntimer.cpp main.cpp
+check_ginac_LDADD = ../ginac/libginac.la
+TESTS = run_checks
index be0c41006602b49325b824df3d2a7923521d7588..2cb929067b3da758361436ac93c6d52c64adf491 100644 (file)
-# This is the Makefile for GiNaC's consistency checks.
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
 
-# Not every make knows what CXX is, so we inherit it together with some other
-# values from configure which checks it anyways:
-CXX = @CXX@
-CXXFLAGS = @CXXFLAGS@
-CPPFLAGS = @CPPFLAGS@ -I../include
-DEFS = @DEFS@
-LIBS = @LIBS@
-LDFLAGS = @LDFLAGS@
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
 
-# Here come the usual install directories in GNU-configure fashion:
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
 prefix = @prefix@
 exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
 libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
 includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CC = @CC@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+DOXYGEN = @DOXYGEN@
+DVIPS = @DVIPS@
+FIG2DEV = @FIG2DEV@
+JADE = @JADE@
+JADETEX = @JADETEX@
+LATEX = @LATEX@
+LD = @LD@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINDEX = @MAKEINDEX@
+MAKEINFO = @MAKEINFO@
+NM = @NM@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+
+noinst_PROGRAMS = check_ginac
+check_ginac_SOURCES = paranoia_check.cpp numeric_output.cpp numeric_consist.cpp \
+  powerlaws.cpp expand_subs.cpp inifcns_consist.cpp differentiation.cpp \
+  poly_gcd.cpp normalization.cpp lsolve_onedim.cpp matrix_checks.cpp \
+  series_expansion.cpp fcntimer.cpp main.cpp
+check_ginac_LDADD = ../ginac/libginac.la
+TESTS = run_checks
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(noinst_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+check_ginac_OBJECTS =  paranoia_check.o numeric_output.o \
+numeric_consist.o powerlaws.o expand_subs.o inifcns_consist.o \
+differentiation.o poly_gcd.o normalization.o lsolve_onedim.o \
+matrix_checks.o series_expansion.o fcntimer.o main.o
+check_ginac_DEPENDENCIES =  ../ginac/libginac.la
+check_ginac_LDFLAGS = 
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+CXXLINK = $(LIBTOOL) --mode=link $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+DEP_FILES =  .deps/differentiation.P .deps/expand_subs.P \
+.deps/fcntimer.P .deps/inifcns_consist.P .deps/lsolve_onedim.P \
+.deps/main.P .deps/matrix_checks.P .deps/normalization.P \
+.deps/numeric_consist.P .deps/numeric_output.P .deps/paranoia_check.P \
+.deps/poly_gcd.P .deps/powerlaws.P .deps/series_expansion.P
+CXXMKDEP = $(CXX) -M $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+SOURCES = $(check_ginac_SOURCES)
+OBJECTS = $(check_ginac_OBJECTS)
+
+all: Makefile $(PROGRAMS)
+
+.SUFFIXES:
+.SUFFIXES: .S .c .cpp .lo .o .s
+$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu check/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstPROGRAMS:
+
+clean-noinstPROGRAMS:
+       -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+distclean-noinstPROGRAMS:
+
+maintainer-clean-noinstPROGRAMS:
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+check_ginac: $(check_ginac_OBJECTS) $(check_ginac_DEPENDENCIES)
+       @rm -f check_ginac
+       $(CXXLINK) $(check_ginac_LDFLAGS) $(check_ginac_OBJECTS) $(check_ginac_LDADD) $(LIBS)
+.cpp.o:
+       $(CXXCOMPILE) -c $<
+.cpp.lo:
+       $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = check
+
+distdir: $(DISTFILES)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(top_distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu check/Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+
+maintainer-clean-depend:
+       -rm -rf .deps
+
+%.o: %.c
+       @echo '$(COMPILE) -c $<'; \
+       $(COMPILE) -Wp,-MD,.deps/$(*F).P -c $<
+
+%.lo: %.c
+       @echo '$(LTCOMPILE) -c $<'; \
+       $(LTCOMPILE) -Wp,-MD,.deps/$(*F).p -c $<
+       @-sed -e 's/^\([^:]*\)\.o:/\1.lo \1.o:/' \
+         < .deps/$(*F).p > .deps/$(*F).P
+       @-rm -f .deps/$(*F).p
+
+%.o: %.cpp
+       @echo '$(CXXCOMPILE) -c $<'; \
+       $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).P -c $<
+
+%.lo: %.cpp
+       @echo '$(LTCXXCOMPILE) -c $<'; \
+       $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).p -c $<
+       @-sed -e 's/^\([^:]*\)\.o:/\1.lo \1.o:/' \
+         < .deps/$(*F).p > .deps/$(*F).P
+       @-rm -f .deps/$(*F).p
+check-TESTS: $(TESTS)
+       @failed=0; all=0; \
+       srcdir=$(srcdir); export srcdir; \
+       for tst in $(TESTS); do \
+         if test -f $$tst; then dir=.; \
+         else dir="$(srcdir)"; fi; \
+         if $(TESTS_ENVIRONMENT) $$dir/$$tst; then \
+           all=`expr $$all + 1`; \
+           echo "PASS: $$tst"; \
+         elif test $$? -ne 77; then \
+           all=`expr $$all + 1`; \
+           failed=`expr $$failed + 1`; \
+           echo "FAIL: $$tst"; \
+         fi; \
+       done; \
+       if test "$$failed" -eq 0; then \
+         banner="All $$all tests passed"; \
+       else \
+         banner="$$failed of $$all tests failed"; \
+       fi; \
+       dashes=`echo "$$banner" | sed s/./=/g`; \
+       echo "$$dashes"; \
+       echo "$$banner"; \
+       echo "$$dashes"; \
+       test "$$failed" -eq 0
+info:
+dvi:
+check: all
+       $(MAKE) check-TESTS
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-noinstPROGRAMS mostlyclean-compile \
+               mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+               mostlyclean-generic
+
+clean:  clean-noinstPROGRAMS clean-compile clean-libtool clean-tags \
+               clean-depend clean-generic mostlyclean
+
+distclean:  distclean-noinstPROGRAMS distclean-compile distclean-libtool \
+               distclean-tags distclean-depend distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-noinstPROGRAMS \
+               maintainer-clean-compile maintainer-clean-libtool \
+               maintainer-clean-tags maintainer-clean-depend \
+               maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \
+clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend check-TESTS info dvi installcheck install-exec \
+install-data install uninstall all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
 
-# This must be empty unless the user has called configure with --enable-shared:
-shared = @shared@
-
-OBJECTS = paranoia_check.o numeric_output.o numeric_consist.o powerlaws.o \
-          expand_subs.o inifcns_consist.o differentiation.o poly_gcd.o \
-          normalization.o lsolve_onedim.o matrix_checks.o series_expansion.o \
-          fcntimer.o main.o
-
-all: 
-       echo "Please call it with 'make check' from top-level Makefile."
-       echo "Alternatively, you can use this Makefile's targets {shared|static}check"
-       echo "depending on your personal preferences and which library you built."
-
-sharedcheck: ${OBJECTS} ../src/.libs/libginac.so
-       ${CXX} ${LDFLAGS} ${OBJECTS} -Wl,--rpath -Wl,../src/.libs -L../src/.libs -lginac ${LIBS} -o main
-       @echo -n "Running "
-       ./main 2> result.out
-       @echo -n "comparing output: "
-       cmp result.ref result.out
-
-staticcheck: ${OBJECTS} ../src/.libs/libginac.a
-       ${CXX} ${LDFLAGS} ${OBJECTS} ../src/.libs/libginac.a ${LIBS} -o main
-       @echo -n "Running "
-       ./main 2> result.out
-       @echo -n "comparing output: "
-       cmp result.ref result.out
-
-# Special dummy targets:
-.PHONY: clean distclean all sharedcheck staticcheck
-.SUFFIXES: .o .cpp
-.SILENT: all
-
-clean:
-       rm -f *.o main core result.out
-
-distclean: clean
-       rm -f Makefile
-
-# Suffix rules:
-.cpp.o :
-       ${CXX} ${CPPFLAGS} ${CXXFLAGS} ${DEFS} -c $<
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
index 68622d967b1c8a3f82789127b61a286703930407..964df6bffdbec7ea28e93464e8cc0285c83bd48f 100644 (file)
@@ -1,7 +1,7 @@
 // check/check.h
 
-#ifndef _CHECK_H_
-#define _CHECK_H_
+#ifndef CHECK_H
+#define CHECK_H
 
 // fcntimer is defined in timer.cpp and used for timing check functions only:
 unsigned fcntimer(unsigned fcn());
@@ -21,4 +21,4 @@ unsigned matrix_checks();
 unsigned lsolve_onedim();
 unsigned series_expansion();
 
-#endif // ndef _CHECK_H_
+#endif // ndef CHECK_H
index 6537eb3f7eb9eb1dfbfba0d4b95e2e0c9ec2d977..c6838efdb2c56d4d1d96c2fd53e554f413c2028b 100644 (file)
@@ -2,7 +2,7 @@
 
 /* Tests for symbolic differentiation, including various functions. */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 static unsigned check_diff(const ex &e, const symbol &x,
                            const ex &d, unsigned nth=1)
index e29e1777515174291848a49196e081ed36c570a2..9f4105a1f5ea44d9e5ea3132b4b8157c9ea91e7d 100644 (file)
@@ -12,7 +12,7 @@
  *     substitute a0 by -a1 in e
  * after which e should return 0 (without expanding). */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 #define VECSIZE 100
 
index 8eaf15fca778aacdc72f691b6001783946044821..d85bf95edbefb68efba6825aa6fa43d2ae6db34a 100644 (file)
@@ -3,7 +3,7 @@
 /* This test routine applies assorted tests on initially known higher level
  * functions. */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 /* Simple tests on the sine trigonometric function. */
 static unsigned inifcns_consist_sin(void)
index f2dc8c066ee9645da6d938dbceb4d670bef04b3d..270b9eb1114f23c579a2169a3f9053ef744a07bb 100644 (file)
@@ -3,7 +3,7 @@
 /* This test routine does some simple checks on solving a polynomial for a
  * variable. */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 unsigned lsolve_onedim(void)
 {
index 787f92080eae1875c79c0c556d339110ac1bb900..4cf44c6d680fa7201dddd7725a2b8b1a4a2ba49d 100644 (file)
@@ -1,7 +1,7 @@
 // check/main.cpp
 
 #include <stdexcept>
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 #include "check.h"
 
 int main()
@@ -25,6 +25,7 @@ int main()
         }
     } catch (exception const & e) {
         cout << "error: caught an exception: " << e.what() << endl;
+               result++;
     }
     
     if (result) {
index 4be5af73ef5df5b9058237af7c03aad63318ffcc..db2277f5bf0c820e051d20bace58a4d9cc42e28d 100644 (file)
@@ -3,7 +3,7 @@
 /* Here we test manipulations on GiNaC's symbolic matrices. */
 
 #include <stdexcept>
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 static unsigned matrix_determinants(void)
 {
index 89809c1a88715912132e2c83493fe89f77122be3..b3882e6054332f1363e5b5efef9eaa710cd99ceb 100644 (file)
@@ -2,7 +2,7 @@
 
 /* Rational function normalization test-suite. */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 static symbol x("x"), y("y"), z("z");
 
index 9f5582951b2bf0ff97ebb95af30e7c2f95ce9de2..947c850a00a9ef5781fd93fb9053e5eb1b5a5ea2 100644 (file)
@@ -4,7 +4,7 @@
  * boolean tests on these numbers like is_integer() etc... */
 
 #include <stdlib.h>
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 /* Simple and maybe somewhat pointless consistency tests of assorted tests and
  * conversions. */
index f35663ea217ba6efda9941e4547c8bcfd2078d7d..c480676870f73d1f33a4cc2c6d9e0fffd685410c 100644 (file)
@@ -1,6 +1,6 @@
 // check/numeric_output.cpp
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 unsigned numeric_output(void)
 {
index 6504bd856b9c564deb1ba51797700bf0801a4bc8..97ee011d902ab912e756e3e954133e6c80c59822 100644 (file)
@@ -5,7 +5,7 @@
  * a sick behaviour again.  But since we are paranoic and we want to exclude
  * that behaviour for good... */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 // The very first pair of historic problems had its roots in power.cpp and was
 // finally resolved on April 27th. (Fixing the first on April 23rd actually
index ee8b63d47f2e7854aefcf85c4d14f20be83be671..484254487590d4dba3cd610d5a82fa3411bb635e 100644 (file)
@@ -3,7 +3,7 @@
 /* Some test with polynomial GCD calculations. See also the checks for
  * rational function normalization in normalization.cpp. */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 const int MAX_VARIABLES = 5;
 
index 3dc867dfb84830659af53738c681c3c81f33d3b2..e103fed9cf37cb8fafe904de35f8892fc0b8d081 100644 (file)
@@ -3,7 +3,7 @@
 /* Tests for power laws.  You shouldn't try to draw much inspiration from
  * this code, it is a sanity check rather deeply rooted in GiNaC's classes. */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 static unsigned powerlaws1(void)
 {
diff --git a/check/run_checks b/check/run_checks
new file mode 100755 (executable)
index 0000000..1c9e6ba
--- /dev/null
@@ -0,0 +1,5 @@
+#! /bin/sh
+echo "Running checks..."
+./check_ginac 2>result.out
+echo "Comparing output..."
+cmp result.ref result.out
index b5cc110cf8d0227d7b3e88594525dbc8e2e9c78c..e66059deca7ee727b6659e33b16404f8a07e64f4 100644 (file)
@@ -2,7 +2,7 @@
 
 /* Series expansion test (Laurent and Taylor series). */
 
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
 
 static symbol x("x");
 
diff --git a/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..e69de29
index a60a0fc126236cd4889414ba46d0d8cd18f7d9d6..2be7888b39a00d587bb4121155d9dd74608a959e 100644 (file)
@@ -1,11 +1,14 @@
 /* config.h.in.  Generated automatically from configure.in by autoheader.  */
 
-/* Define if you have the ANSI C header files.  */
-#undef STDC_HEADERS
-
 /* Define if lex declares yytext as a char * by default, not a char[].  */
 #undef YYTEXT_POINTER
 
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
 /* Define if you have the strdup function.  */
 #undef HAVE_STRDUP
 
diff --git a/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..e69de29
index 4f04a4caa8f9b1bc87b41a713ae374d39ce635f4..158683c2d377ae6758492d7e37f22e878241febc 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
 #! /bin/sh
 
 # Guess values for system-dependent variables and create Makefiles.
-# Generated automatically using autoconf version 2.13 
+# Generated automatically using autoconf version 2.12 
 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
 #
 # This configure script is free software; the Free Software Foundation
@@ -12,8 +12,18 @@ ac_help=
 ac_default_prefix=/usr/local
 # Any additions from configure.in:
 ac_help="$ac_help
-  --enable-shared         build shared libraries [default=no]
-                          (a static library will still be built as well)"
+  --enable-maintainer-mode enable make rules and dependencies not useful
+                          (and sometimes confusing) to the casual installer"
+ac_help="$ac_help
+  --enable-shared         build shared libraries [default=yes]
+  --enable-shared=PKGS    only build shared libraries if the current package
+                          appears as an element in the PKGS list"
+ac_help="$ac_help
+  --enable-static         build static libraries [default=yes]
+  --enable-static=PKGS    only build shared libraries if the current package
+                          appears as an element in the PKGS list"
+ac_help="$ac_help
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]"
 
 # Initialize some variables set by options.
 # The variables have the same names as the options, with
@@ -52,7 +62,6 @@ mandir='${prefix}/man'
 # Initialize some other variables.
 subdirs=
 MFLAGS= MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
 # Maximum number of lines to put in a shell here document.
 ac_max_here_lines=12
 
@@ -336,7 +345,7 @@ EOF
     verbose=yes ;;
 
   -version | --version | --versio | --versi | --vers)
-    echo "configure generated by autoconf version 2.13"
+    echo "configure generated by autoconf version 2.12"
     exit 0 ;;
 
   -with-* | --with-*)
@@ -454,7 +463,7 @@ echo > confdefs.h
 
 # A filename unique to this package, relative to the directory that
 # configure is in, which we can look for to find out if srcdir is correct.
-ac_unique_file=include/GiNaC/ginac.h
+ac_unique_file=ginac/basic.cpp
 
 # Find the source files, if location was not specified.
 if test -z "$srcdir"; then
@@ -506,11 +515,9 @@ ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cc_cross
 
-ac_exeext=
-ac_objext=o
 if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
   # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
   if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
@@ -526,36 +533,293 @@ fi
 
 
 
-GiNaC_Major_Version=0
-GiNaC_Minor_Version=0
-GiNaC_Micro_Version=40
-GiNaC_Version="${GiNaC_Major_Version}.${GiNaC_Minor_Version}.${GiNaC_Micro_Version}"
-LibGiNaC_Ver="${GiNaC_Major_Version}:${GiNaC_Micro_Version}:${GiNaC_Minor_Version}"
 
-# Check whether --enable-shared or --disable-shared was given.
-if test "${enable_shared+set}" = set; then
-  enableval="$enable_shared"
-  shared=${enableval}
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:570: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS=        }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      for ac_prog in ginstall installbsd scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+         if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           # OSF/1 installbsd also uses dspmsg, but is usable.
+           :
+         else
+           ac_cv_path_install="$ac_dir/$ac_prog -c"
+           break 2
+         fi
+       fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:623: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:680: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+       @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=GiNaC
+
+VERSION=0.4
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:726: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:739: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:752: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:765: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
 else
-  shared="no"
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
 fi
 
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:778: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+
+echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
+echo "configure:792: checking whether to enable maintainer-specific portions of Makefiles" >&5
+    # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+  enableval="$enable_maintainer_mode"
+  USE_MAINTAINER_MODE=$enableval
+else
+  USE_MAINTAINER_MODE=no
+fi
+
+  echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6
+  if test $USE_MAINTAINER_MODE = yes; then
+    MAINT=
+  else
+    MAINT='#M#'
+  fi
+  
+
 
-for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:550: checking for $ac_word" >&5
+echo "configure:815: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$CXX"; then
   ac_cv_prog_CXX="$CXX" # Let the user override the test.
 else
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_prog_CXX="$ac_prog"
@@ -578,23 +842,21 @@ test -n "$CXX" || CXX="gcc"
 
 
 echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:582: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+echo "configure:846: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
 
 ac_ext=C
 # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+ac_link='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cxx_cross
 
-cat > conftest.$ac_ext << EOF
-
-#line 593 "configure"
+cat > conftest.$ac_ext <<EOF
+#line 856 "configure"
 #include "confdefs.h"
-
-int main(){return(0);}
+main(){return(0);}
 EOF
-if { (eval echo configure:598: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:860: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   ac_cv_prog_cxx_works=yes
   # If we can't run a trivial program, we are probably using a cross compiler.
   if (./conftest; exit) 2>/dev/null; then
@@ -612,7 +874,7 @@ ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cc_cross
 
 echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
@@ -620,12 +882,12 @@ if test $ac_cv_prog_cxx_works = no; then
   { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
 fi
 echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:624: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:886: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
 echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
 cross_compiling=$ac_cv_prog_cxx_cross
 
 echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
-echo "configure:629: checking whether we are using GNU C++" >&5
+echo "configure:891: checking whether we are using GNU C++" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -634,7 +896,7 @@ else
   yes;
 #endif
 EOF
-if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:638: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:900: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
   ac_cv_prog_gxx=yes
 else
   ac_cv_prog_gxx=no
@@ -645,15 +907,11 @@ echo "$ac_t""$ac_cv_prog_gxx" 1>&6
 
 if test $ac_cv_prog_gxx = yes; then
   GXX=yes
-else
-  GXX=
-fi
-
-ac_test_CXXFLAGS="${CXXFLAGS+set}"
-ac_save_CXXFLAGS="$CXXFLAGS"
-CXXFLAGS=
-echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
-echo "configure:657: checking whether ${CXX-g++} accepts -g" >&5
+  ac_test_CXXFLAGS="${CXXFLAGS+set}"
+  ac_save_CXXFLAGS="$CXXFLAGS"
+  CXXFLAGS=
+  echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:915: checking whether ${CXX-g++} accepts -g" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -668,24 +926,20 @@ rm -f conftest*
 fi
 
 echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
-if test "$ac_test_CXXFLAGS" = set; then
-  CXXFLAGS="$ac_save_CXXFLAGS"
-elif test $ac_cv_prog_cxx_g = yes; then
-  if test "$GXX" = yes; then
+  if test "$ac_test_CXXFLAGS" = set; then
+    CXXFLAGS="$ac_save_CXXFLAGS"
+  elif test $ac_cv_prog_cxx_g = yes; then
     CXXFLAGS="-g -O2"
   else
-    CXXFLAGS="-g"
-  fi
-else
-  if test "$GXX" = yes; then
     CXXFLAGS="-O2"
-  else
-    CXXFLAGS=
   fi
+else
+  GXX=
+  test "${CXXFLAGS+set}" = set || CXXFLAGS="-g"
 fi
 
 echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6
-echo "configure:689: checking how to run the C++ preprocessor" >&5
+echo "configure:943: checking how to run the C++ preprocessor" >&5
 if test -z "$CXXCPP"; then
 if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -694,17 +948,17 @@ else
 # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+ac_link='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cxx_cross
   CXXCPP="${CXX-g++} -E"
   cat > conftest.$ac_ext <<EOF
-#line 702 "configure"
+#line 956 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:707: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+{ (eval echo configure:961: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   :
 else
@@ -720,530 +974,585 @@ ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
 cross_compiling=$ac_cv_prog_cc_cross
 fi
 fi
 CXXCPP="$ac_cv_prog_CXXCPP"
 echo "$ac_t""$CXXCPP" 1>&6
 
-ac_ext=C
-# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cxx_cross
 
-echo $ac_n "checking for cout in -lstdc++""... $ac_c" 1>&6
-echo "configure:739: checking for cout in -lstdc++" >&5
-ac_lib_var=`echo stdc++'_'cout | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lstdc++  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 747 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char cout();
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
 
-int main() {
-cout()
-; return 0; }
-EOF
-if { (eval echo configure:761: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
+# Check whether --enable-shared or --disable-shared was given.
+if test "${enable_shared+set}" = set; then
+  enableval="$enable_shared"
+  p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+  enable_shared=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_shared=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
 else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
+  enable_shared=yes
+fi
+
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+  enableval="$enable_static"
+  p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+  enable_static=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_static=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+else
+  enable_static=yes
 fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
 
+
+# Make sure we can run config.sub.
+if $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
 fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo stdc++ | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
 
-  LIBS="-lstdc++ $LIBS"
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:1041: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+  case $nonopt in
+  NONE)
+    if host_alias=`$ac_config_guess`; then :
+    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+    fi ;;
+  *) host_alias=$nonopt ;;
+  esac ;;
+esac
+
+host=`$ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
 
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1064: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
 else
   echo "$ac_t""no" 1>&6
 fi
 
-for ac_hdr in iostream vector map string list typeinfo iterator strstream stdexcept algorithm
-do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:792: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1093: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
-  cat > conftest.$ac_ext <<EOF
-#line 797 "configure"
-#include "confdefs.h"
-#include <$ac_hdr>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:802: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=yes"
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
 else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=no"
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
 fi
-rm -f conftest*
 fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
 else
   echo "$ac_t""no" 1>&6
-{ echo "configure: error: need to have ANSI compliant headers" 1>&2; exit 1; }
 fi
-done
-
 
-    for ac_hdr in CLN/cln.h
-do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:834: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1122: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
-  cat > conftest.$ac_ext <<EOF
-#line 839 "configure"
-#include "confdefs.h"
-#include <$ac_hdr>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:844: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=yes"
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
 else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=no"
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  ac_prog_rejected=no
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+       continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
 fi
-rm -f conftest*
 fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
-else
-  echo "$ac_t""no" 1>&6
-for ac_hdr in cln.h
-do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:871: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 876 "configure"
-#include "confdefs.h"
-#include <$ac_hdr>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:881: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=yes"
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=no"
 fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
 else
   echo "$ac_t""no" 1>&6
-{ echo "configure: error: cannot find header for Bruno Haible's CLN" 1>&2; exit 1; };
-        
 fi
-done
 
-    
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
 fi
-done
 
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:1170: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
 
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
 
-    echo $ac_n "checking how to link with libcln""... $ac_c" 1>&6
-echo "configure:916: checking how to link with libcln" >&5
-    saved_LIBS="${LIBS}"
-    if eval "test \"`echo '$''{'ginac_cv_lib_cln_link'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  LIBS="-lcln"
-        case "${ac_cv_header_CLN_cln_h}" in
-        "yes")
-            cat > conftest.$ac_ext <<EOF
-#line 925 "configure"
-#include "confdefs.h"
-#include <CLN/cln.h>
-int main() {
-factorial(1);
-; return 0; }
-EOF
-if { (eval echo configure:932: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  ginac_cv_lib_cln_link="-lcln"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ginac_cv_lib_cln_link="fail"
-fi
-rm -f conftest*
-            ;;
-        *)
-            cat > conftest.$ac_ext <<EOF
-#line 945 "configure"
+cat > conftest.$ac_ext <<EOF
+#line 1180 "configure"
 #include "confdefs.h"
-#include <cln.h>
-int main() {
-factorial(1);
-; return 0; }
+main(){return(0);}
 EOF
-if { (eval echo configure:952: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  ginac_cv_lib_cln_link="-lcln"
+if { (eval echo configure:1184: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ginac_cv_lib_cln_link="fail"
+  ac_cv_prog_cc_works=no
 fi
-rm -f conftest*
-            ;;
-        esac
-    
+rm -fr conftest*
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
 fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1204: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
 
-    case "${ginac_cv_lib_cln_link}" in
-    "-lcln")
-        LIBS="-lcln ${saved_LIBS}"
-        echo "$ac_t""-lcln" 1>&6
-        
-    echo $ac_n "checking whether libcln behaves sane""... $ac_c" 1>&6
-echo "configure:973: checking whether libcln behaves sane" >&5
-    if eval "test \"`echo '$''{'ginac_cv_lib_cln_integrity'+set}'`\" = set"; then
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:1209: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
-  
-        case "${ac_cv_header_CLN_cln_h}" in
-        "yes")
-            if test "$cross_compiling" = yes; then
-  ginac_cv_lib_cln_integrity="guessing sane"
-else
-  cat > conftest.$ac_ext <<EOF
-#line 984 "configure"
-#include "confdefs.h"
-#ifdef __cplusplus
-extern "C" void exit(int);
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
 #endif
-#include <CLN/cln.h>
-int main() {
-cl_RA q(3); q = q/2; cl_RA p(3); p = p/2;
-if (q+p != 3) return 1; else return 0;
-}
 EOF
-if { (eval echo configure:995: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  ginac_cv_lib_cln_integrity="sane"
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1218: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
 else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ginac_cv_lib_cln_integrity="insane"
+  ac_cv_prog_gcc=no
 fi
-rm -fr conftest*
 fi
 
-            ;;
-        *)
-            if test "$cross_compiling" = yes; then
-  ginac_cv_lib_cln_integrity="guessing sane"
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+  ac_test_CFLAGS="${CFLAGS+set}"
+  ac_save_CFLAGS="$CFLAGS"
+  CFLAGS=
+  echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:1233: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
 else
-  cat > conftest.$ac_ext <<EOF
-#line 1013 "configure"
-#include "confdefs.h"
-#ifdef __cplusplus
-extern "C" void exit(int);
-#endif
-#include <cln.h>
-int main() {
-cl_RA q(3); q = q/2; cl_RA p(3); p = p/2;
-if (q+p != 3) return 1; else return 0;
-}
-EOF
-if { (eval echo configure:1024: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  ginac_cv_lib_cln_integrity="sane"
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
 else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ginac_cv_lib_cln_integrity="insane"
+  ac_cv_prog_cc_g=no
 fi
-rm -fr conftest*
+rm -f conftest*
+
 fi
 
-            ;;
-        esac
-    
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+  if test "$ac_test_CFLAGS" = set; then
+    CFLAGS="$ac_save_CFLAGS"
+  elif test $ac_cv_prog_cc_g = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-O2"
+  fi
+else
+  GCC=
+  test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+  withval="$with_gnu_ld"
+  test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
 fi
 
-    case "${ginac_cv_lib_cln_integrity}" in
-    "sane")
-        echo "$ac_t""yes" 1>&6
-    ;;
-    "insane")
-        echo "$ac_t""no" 1>&6
-        echo "configure: warning: maybe version of libcln is older than 1.0.2?" 1>&2
-    ;;
-    "guessing sane")
-        echo "$ac_t""hopefully" 1>&6
-    ;;
-    *)
-        echo "configure: warning: you found a bug in the configure script!" 1>&2
-    ;;
-    esac
 
+ac_prog=ld
+if test "$ac_cv_prog_gcc" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6
+echo "configure:1273: checking for ld used by GCC" >&5
+  ac_prog=`($CC -print-prog-name=ld) 2>&5`
+  case "$ac_prog" in
+  # Accept absolute paths.
+  /* | A-Za-z:\\*)
+    test -z "$LD" && LD="$ac_prog"
     ;;
-    "fail")
-        LIBS="${saved_LIBS}"
-        echo "$ac_t""" 1>&6
-        echo "configure: warning: linking with libcln failed" 1>&2
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
     ;;
-    *)
-        LIBS="${saved_LIBS}"
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
     ;;
-    esac
-
-ac_aux_dir=
-for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
-  if test -f $ac_dir/install-sh; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install-sh -c"
-    break
-  elif test -f $ac_dir/install.sh; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install.sh -c"
-    break
-  fi
-done
-if test -z "$ac_aux_dir"; then
-  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+  esac
+elif test "$with_gnu_ld" = yes; then
+  echo $ac_n "checking for GNU ld""... $ac_c" 1>&6
+echo "configure:1291: checking for GNU ld" >&5
+else
+  echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6
+echo "configure:1294: checking for non-GNU ld" >&5
 fi
-ac_config_guess=$ac_aux_dir/config.guess
-ac_config_sub=$ac_aux_dir/config.sub
-ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
-
-# Find a good install program.  We prefer a C program (faster),
-# so one script is as good as another.  But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# ./install, which can be erroneously created by make from ./install.sh.
-echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:1099: checking for a BSD compatible install" >&5
-if test -z "$INSTALL"; then
-if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
-    IFS="${IFS=        }"; ac_save_IFS="$IFS"; IFS=":"
+  if test -z "$LD"; then
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
   for ac_dir in $PATH; do
-    # Account for people who put trailing slashes in PATH elements.
-    case "$ac_dir/" in
-    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
-    *)
-      # OSF1 and SCO ODT 3.0 have their own names for install.
-      # Don't use installbsd from OSF since it installs stuff as root
-      # by default.
-      for ac_prog in ginstall scoinst install; do
-        if test -f $ac_dir/$ac_prog; then
-         if test $ac_prog = install &&
-            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
-           # AIX install.  It has an incompatible calling convention.
-           :
-         else
-           ac_cv_path_install="$ac_dir/$ac_prog -c"
-           break 2
-         fi
-       fi
-      done
-      ;;
-    esac
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog"; then
+      ac_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+       test "$with_gnu_ld" != no && break
+      else
+        test "$with_gnu_ld" != yes && break
+      fi
+    fi
   done
-  IFS="$ac_save_IFS"
+  IFS="$ac_save_ifs"
+else
+  ac_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$ac_cv_path_LD"
+if test -n "$LD"; then
+  echo "$ac_t""$LD" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; }
 
+echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6
+echo "configure:1330: checking if the linker ($LD) is GNU ld" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+  ac_cv_prog_gnu_ld=yes
+else
+  ac_cv_prog_gnu_ld=no
 fi
-  if test "${ac_cv_path_install+set}" = set; then
-    INSTALL="$ac_cv_path_install"
-  else
-    # As a last resort, use the slow shell script.  We don't cache a
-    # path for INSTALL within a source directory, because that will
-    # break other packages using the cache if that directory is
-    # removed, or if the path is relative.
-    INSTALL="$ac_install_sh"
-  fi
 fi
-echo "$ac_t""$INSTALL" 1>&6
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
 
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6
 
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 
-# Extract the first word of "makedepend", so it can be a program name with args.
-set dummy makedepend; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1154: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_path_MAKEDEPEND'+set}'`\" = set"; then
+echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6
+echo "configure:1346: checking for BSD-compatible nm" >&5
+if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
-  case "$MAKEDEPEND" in
-  /*)
-  ac_cv_path_MAKEDEPEND="$MAKEDEPEND" # Let the user override the test with a path.
+  case "$NM" in
+/* | A-Za-z:\\*)
+  ac_cv_path_NM="$NM" # Let the user override the test with a path.
   ;;
-  ?:/*)                         
-  ac_cv_path_MAKEDEPEND="$MAKEDEPEND" # Let the user override the test with a dos path.
-  ;;
-  *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+*)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do
     test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$ac_word; then
-      ac_cv_path_MAKEDEPEND="$ac_dir/$ac_word"
+    if test -f $ac_dir/nm; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -B"
+      elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -p"
+      else
+        ac_cv_path_NM="$ac_dir/nm"
+      fi
       break
     fi
   done
   IFS="$ac_save_ifs"
-  test -z "$ac_cv_path_MAKEDEPEND" && ac_cv_path_MAKEDEPEND=""""
+  test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
   ;;
 esac
 fi
-MAKEDEPEND="$ac_cv_path_MAKEDEPEND"
-if test -n "$MAKEDEPEND"; then
-  echo "$ac_t""$MAKEDEPEND" 1>&6
+
+NM="$ac_cv_path_NM"
+echo "$ac_t""$NM" 1>&6
+
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1383: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
 else
   echo "$ac_t""no" 1>&6
 fi
 
-case "${shared}" in
-"yes"|"Yes"|"YES")      # Default-enable ("yes") or user was nitpicking:
-    shared="shlib";
-    # Extract the first word of "libtool", so it can be a program name with args.
-set dummy libtool; ac_word=$2
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+# Check for any special flags to pass to ltconfig.
+libtool_flags=
+test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
+test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
+test "$silent" = yes && libtool_flags="$libtool_flags --silent"
+test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
+test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case "$host" in
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line 1419 "configure"' > conftest.$ac_ext
+  if { (eval echo configure:1420: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  CFLAGS="$CFLAGS -belf"
+  ;;
+esac
+
+# Actually configure libtool.  ac_aux_dir is where install-sh is found.
+CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
+LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \
+$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \
+|| { echo "configure: error: libtool configure failed" 1>&2; exit 1; }
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1450: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1465 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1471: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1482 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1488: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+missing_dir=`cd $ac_aux_dir && pwd`
+for ac_prog in flex lex
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1193: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_path_LIBTOOL'+set}'`\" = set"; then
+echo "configure:1516: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
-  case "$LIBTOOL" in
-  /*)
-  ac_cv_path_LIBTOOL="$LIBTOOL" # Let the user override the test with a path.
-  ;;
-  ?:/*)                         
-  ac_cv_path_LIBTOOL="$LIBTOOL" # Let the user override the test with a dos path.
-  ;;
-  *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+  if test -n "$LEX"; then
+  ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
-      ac_cv_path_LIBTOOL="$ac_dir/$ac_word"
+      ac_cv_prog_LEX="$ac_prog"
       break
     fi
   done
   IFS="$ac_save_ifs"
-  test -z "$ac_cv_path_LIBTOOL" && ac_cv_path_LIBTOOL=""""
-  ;;
-esac
 fi
-LIBTOOL="$ac_cv_path_LIBTOOL"
-if test -n "$LIBTOOL"; then
-  echo "$ac_t""$LIBTOOL" 1>&6
+fi
+LEX="$ac_cv_prog_LEX"
+if test -n "$LEX"; then
+  echo "$ac_t""$LEX" 1>&6
 else
   echo "$ac_t""no" 1>&6
 fi
 
-    if test "${LIBTOOL}" == ""; then
-        echo "configure: warning: libtool not found: building static lib only" 1>&2
-        shared="";
-    fi
-    ;;
-*)      # Default, default-disable ("no") or user entered bogus:
-    shared="";
-    ;;
-esac
+test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=""$missing_dir/missing flex""
+
 # Extract the first word of "flex", so it can be a program name with args.
 set dummy flex; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1238: checking for $ac_word" >&5
+echo "configure:1548: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$LEX"; then
   ac_cv_prog_LEX="$LEX" # Let the user override the test.
 else
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_prog_LEX="flex"
@@ -1268,7 +1577,7 @@ then
   *) ac_lib=l ;;
   esac
   echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6
-echo "configure:1272: checking for yywrap in -l$ac_lib" >&5
+echo "configure:1581: checking for yywrap in -l$ac_lib" >&5
 ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1276,12 +1585,9 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-l$ac_lib  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1280 "configure"
+#line 1589 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
-#ifdef __cplusplus
-extern "C"
-#endif
 /* We use char because int might match the return type of a gcc2
     builtin and then its argument prototype would still apply.  */
 char yywrap();
@@ -1290,7 +1596,7 @@ int main() {
 yywrap()
 ; return 0; }
 EOF
-if { (eval echo configure:1294: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1600: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1312,21 +1618,82 @@ fi
 
 fi
 
+echo $ac_n "checking lex output file root""... $ac_c" 1>&6
+echo "configure:1623: checking lex output file root" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # The minimal lex program is just a single line: %%.  But some broken lexes
+# (Solaris, I think it was) want two %% lines, so accommodate them.
+echo '%%
+%%' | $LEX
+if test -f lex.yy.c; then
+  ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+  ac_cv_prog_lex_root=lexyy
+else
+  { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; }
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_lex_root" 1>&6
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6
+echo "configure:1644: checking whether yytext is a pointer" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent. Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c
+ac_save_LIBS="$LIBS"
+LIBS="$LIBS $LEXLIB"
+cat > conftest.$ac_ext <<EOF
+#line 1656 "configure"
+#include "confdefs.h"
+`cat $LEX_OUTPUT_ROOT.c`
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:1663: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ac_cv_prog_lex_yytext_pointer=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+rm -f "${LEX_OUTPUT_ROOT}.c"
+
+fi
+
+echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+  cat >> confdefs.h <<\EOF
+#define YYTEXT_POINTER 1
+EOF
+
+fi
+
 for ac_prog in 'bison -y' byacc
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1321: checking for $ac_word" >&5
+echo "configure:1689: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test -n "$YACC"; then
   ac_cv_prog_YACC="$YACC" # Let the user override the test.
 else
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_prog_YACC="$ac_prog"
@@ -1342,196 +1709,369 @@ if test -n "$YACC"; then
 else
   echo "$ac_t""no" 1>&6
 fi
-
-test -n "$YACC" && break
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+
+echo $ac_n "checking for cout in -lstdc++""... $ac_c" 1>&6
+echo "configure:1728: checking for cout in -lstdc++" >&5
+ac_lib_var=`echo stdc++'_'cout | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lstdc++  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1736 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char cout();
+
+int main() {
+cout()
+; return 0; }
+EOF
+if { (eval echo configure:1750: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo stdc++ | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lstdc++ $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+for ac_hdr in iostream vector map string list typeinfo iterator strstream stdexcept algorithm
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1782: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1787 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1792: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: need to have ANSI compliant headers" 1>&2; exit 1; }
+fi
 done
-test -n "$YACC" || YACC="yacc"
 
-echo $ac_n "checking lex output file root""... $ac_c" 1>&6
-echo "configure:1352: checking lex output file root" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  # The minimal lex program is just a single line: %%.  But some broken lexes
-# (Solaris, I think it was) want two %% lines, so accommodate them.
-echo '%%
-%%' | $LEX
-if test -f lex.yy.c; then
-  ac_cv_prog_lex_root=lex.yy
-elif test -f lexyy.c; then
-  ac_cv_prog_lex_root=lexyy
-else
-  { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; }
-fi
-fi
 
-echo "$ac_t""$ac_cv_prog_lex_root" 1>&6
-LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
 
-echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6
-echo "configure:1373: checking whether yytext is a pointer" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then
+    for ac_hdr in CLN/cln.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1825: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
-  # POSIX says lex can declare yytext either as a pointer or an array; the
-# default is implementation-dependent. Figure out which it is, since
-# not all implementations provide the %pointer and %array declarations.
-ac_cv_prog_lex_yytext_pointer=no
-echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c
-ac_save_LIBS="$LIBS"
-LIBS="$LIBS $LEXLIB"
-cat > conftest.$ac_ext <<EOF
-#line 1385 "configure"
+  cat > conftest.$ac_ext <<EOF
+#line 1830 "configure"
 #include "confdefs.h"
-`cat $LEX_OUTPUT_ROOT.c`
-int main() {
-
-; return 0; }
+#include <$ac_hdr>
 EOF
-if { (eval echo configure:1392: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1835: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
   rm -rf conftest*
-  ac_cv_prog_lex_yytext_pointer=yes
+  eval "ac_cv_header_$ac_safe=yes"
 else
+  echo "$ac_err" >&5
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
 fi
 rm -f conftest*
-LIBS="$ac_save_LIBS"
-rm -f "${LEX_OUTPUT_ROOT}.c"
-
 fi
-
-echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6
-if test $ac_cv_prog_lex_yytext_pointer = yes; then
-  cat >> confdefs.h <<\EOF
-#define YYTEXT_POINTER 1
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
 EOF
-
-fi
-
-echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1414: checking for ANSI C header files" >&5
-if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+else
+  echo "$ac_t""no" 1>&6
+for ac_hdr in cln.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1862: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1419 "configure"
+#line 1867 "configure"
 #include "confdefs.h"
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
+#include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1427: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+{ (eval echo configure:1872: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   rm -rf conftest*
-  ac_cv_header_stdc=yes
+  eval "ac_cv_header_$ac_safe=yes"
 else
   echo "$ac_err" >&5
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
   rm -rf conftest*
-  ac_cv_header_stdc=no
+  eval "ac_cv_header_$ac_safe=no"
 fi
 rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: cannot find header for Bruno Haible's CLN" 1>&2; exit 1; };
+        
+fi
+done
 
-if test $ac_cv_header_stdc = yes; then
-  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1444 "configure"
+    
+fi
+done
+
+
+
+    echo $ac_n "checking how to link with libcln""... $ac_c" 1>&6
+echo "configure:1907: checking how to link with libcln" >&5
+    saved_LIBS="${LIBS}"
+    if eval "test \"`echo '$''{'ginac_cv_lib_cln_link'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  LIBS="-lcln"
+        case "${ac_cv_header_CLN_cln_h}" in
+        "yes")
+            cat > conftest.$ac_ext <<EOF
+#line 1916 "configure"
 #include "confdefs.h"
-#include <string.h>
+#include <CLN/cln.h>
+int main() {
+factorial(1);
+; return 0; }
 EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "memchr" >/dev/null 2>&1; then
-  :
+if { (eval echo configure:1923: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ginac_cv_lib_cln_link="-lcln"
 else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
   rm -rf conftest*
-  ac_cv_header_stdc=no
+  ginac_cv_lib_cln_link="fail"
 fi
 rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1462 "configure"
+            ;;
+        *)
+            cat > conftest.$ac_ext <<EOF
+#line 1936 "configure"
 #include "confdefs.h"
-#include <stdlib.h>
+#include <cln.h>
+int main() {
+factorial(1);
+; return 0; }
 EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "free" >/dev/null 2>&1; then
-  :
+if { (eval echo configure:1943: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ginac_cv_lib_cln_link="-lcln"
 else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
   rm -rf conftest*
-  ac_cv_header_stdc=no
+  ginac_cv_lib_cln_link="fail"
 fi
 rm -f conftest*
-
+            ;;
+        esac
+    
 fi
 
-if test $ac_cv_header_stdc = yes; then
-  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-if test "$cross_compiling" = yes; then
-  :
+    case "${ginac_cv_lib_cln_link}" in
+    "-lcln")
+        LIBS="-lcln ${saved_LIBS}"
+        echo "$ac_t""-lcln" 1>&6
+        
+    echo $ac_n "checking whether libcln behaves sane""... $ac_c" 1>&6
+echo "configure:1964: checking whether libcln behaves sane" >&5
+    if eval "test \"`echo '$''{'ginac_cv_lib_cln_integrity'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+        case "${ac_cv_header_CLN_cln_h}" in
+        "yes")
+            if test "$cross_compiling" = yes; then
+  ginac_cv_lib_cln_integrity="guessing sane"
 else
   cat > conftest.$ac_ext <<EOF
-#line 1483 "configure"
+#line 1975 "configure"
 #include "confdefs.h"
 #ifdef __cplusplus
 extern "C" void exit(int);
 #endif
-#include <ctype.h>
-#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int main () { int i; for (i = 0; i < 256; i++)
-if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
-exit (0); }
-
+#include <CLN/cln.h>
+int main() {
+cl_RA q(3); q = q/2; cl_RA p(3); p = p/2;
+if (q+p != 3) return 1; else return 0;
+}
 EOF
-if { (eval echo configure:1497: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1986: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
 then
-  :
+  ginac_cv_lib_cln_integrity="sane"
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
   rm -fr conftest*
-  ac_cv_header_stdc=no
+  ginac_cv_lib_cln_integrity="insane"
 fi
 rm -fr conftest*
 fi
 
+            ;;
+        *)
+            if test "$cross_compiling" = yes; then
+  ginac_cv_lib_cln_integrity="guessing sane"
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2004 "configure"
+#include "confdefs.h"
+#ifdef __cplusplus
+extern "C" void exit(int);
+#endif
+#include <cln.h>
+int main() {
+cl_RA q(3); q = q/2; cl_RA p(3); p = p/2;
+if (q+p != 3) return 1; else return 0;
+}
+EOF
+if { (eval echo configure:2015: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  ginac_cv_lib_cln_integrity="sane"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ginac_cv_lib_cln_integrity="insane"
 fi
+rm -fr conftest*
 fi
 
-echo "$ac_t""$ac_cv_header_stdc" 1>&6
-if test $ac_cv_header_stdc = yes; then
-  cat >> confdefs.h <<\EOF
-#define STDC_HEADERS 1
-EOF
-
+            ;;
+        esac
+    
 fi
 
+    case "${ginac_cv_lib_cln_integrity}" in
+    "sane")
+        echo "$ac_t""yes" 1>&6
+    ;;
+    "insane")
+        echo "$ac_t""no" 1>&6
+        echo "configure: warning: maybe version of libcln is older than 1.0.2?" 1>&2
+    ;;
+    "guessing sane")
+        echo "$ac_t""hopefully" 1>&6
+    ;;
+    *)
+        echo "configure: warning: you found a bug in the configure script!" 1>&2
+    ;;
+    esac
+
+    ;;
+    "fail")
+        LIBS="${saved_LIBS}"
+        echo "$ac_t""" 1>&6
+        echo "configure: warning: linking with libcln failed" 1>&2
+    ;;
+    *)
+        LIBS="${saved_LIBS}"
+    ;;
+    esac
+
+
 for ac_hdr in unistd.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1524: checking for $ac_hdr" >&5
+echo "configure:2064: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1529 "configure"
+#line 2069 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1534: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+{ (eval echo configure:2074: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   rm -rf conftest*
   eval "ac_cv_header_$ac_safe=yes"
@@ -1559,12 +2099,12 @@ done
 for ac_func in strdup
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1563: checking for $ac_func" >&5
+echo "configure:2103: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1568 "configure"
+#line 2108 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -1590,7 +2130,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1594: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2134: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -1611,25 +2151,27 @@ EOF
  
 else
   echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.o"
 fi
 done
 
+
 for ac_hdr in readline/readline.h readline/history.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1622: checking for $ac_hdr" >&5
+echo "configure:2164: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1627 "configure"
+#line 2169 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1632: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+{ (eval echo configure:2174: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   rm -rf conftest*
   eval "ac_cv_header_$ac_safe=yes"
@@ -1651,12 +2193,11 @@ EOF
  
 else
   echo "$ac_t""no" 1>&6
-{ echo "configure: error: need to have GNU readline headers" 1>&2; exit 1; }
 fi
 done
 
 echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
-echo "configure:1660: checking for readline in -lreadline" >&5
+echo "configure:2201: checking for readline in -lreadline" >&5
 ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1664,7 +2205,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lreadline  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1668 "configure"
+#line 2209 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 #ifdef __cplusplus
@@ -1678,7 +2219,7 @@ int main() {
 readline()
 ; return 0; }
 EOF
-if { (eval echo configure:1682: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2223: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1703,13 +2244,13 @@ EOF
 
 else
   echo "$ac_t""no" 1>&6
-{ echo "configure: error: need to have GNU readline library" 1>&2; exit 1; }
 fi
 
+
 # Extract the first word of "doxygen", so it can be a program name with args.
 set dummy doxygen; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1713: checking for $ac_word" >&5
+echo "configure:2254: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_DOXYGEN'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1717,13 +2258,9 @@ else
   /*)
   ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a path.
   ;;
-  ?:/*)                         
-  ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a dos path.
-  ;;
   *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_path_DOXYGEN="$ac_dir/$ac_word"
@@ -1745,7 +2282,7 @@ fi
 # Extract the first word of "latex", so it can be a program name with args.
 set dummy latex; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1749: checking for $ac_word" >&5
+echo "configure:2286: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_LATEX'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1753,13 +2290,9 @@ else
   /*)
   ac_cv_path_LATEX="$LATEX" # Let the user override the test with a path.
   ;;
-  ?:/*)                         
-  ac_cv_path_LATEX="$LATEX" # Let the user override the test with a dos path.
-  ;;
   *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_path_LATEX="$ac_dir/$ac_word"
@@ -1781,7 +2314,7 @@ fi
 # Extract the first word of "makeindex", so it can be a program name with args.
 set dummy makeindex; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1785: checking for $ac_word" >&5
+echo "configure:2318: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_MAKEINDEX'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1789,13 +2322,9 @@ else
   /*)
   ac_cv_path_MAKEINDEX="$MAKEINDEX" # Let the user override the test with a path.
   ;;
-  ?:/*)                         
-  ac_cv_path_MAKEINDEX="$MAKEINDEX" # Let the user override the test with a dos path.
-  ;;
   *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_path_MAKEINDEX="$ac_dir/$ac_word"
@@ -1817,7 +2346,7 @@ fi
 # Extract the first word of "dvips", so it can be a program name with args.
 set dummy dvips; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1821: checking for $ac_word" >&5
+echo "configure:2350: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_DVIPS'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1825,13 +2354,9 @@ else
   /*)
   ac_cv_path_DVIPS="$DVIPS" # Let the user override the test with a path.
   ;;
-  ?:/*)                         
-  ac_cv_path_DVIPS="$DVIPS" # Let the user override the test with a dos path.
-  ;;
   *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_path_DVIPS="$ac_dir/$ac_word"
@@ -1853,7 +2378,7 @@ fi
 # Extract the first word of "fig2dev", so it can be a program name with args.
 set dummy fig2dev; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1857: checking for $ac_word" >&5
+echo "configure:2382: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_FIG2DEV'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1861,13 +2386,9 @@ else
   /*)
   ac_cv_path_FIG2DEV="$FIG2DEV" # Let the user override the test with a path.
   ;;
-  ?:/*)                         
-  ac_cv_path_FIG2DEV="$FIG2DEV" # Let the user override the test with a dos path.
-  ;;
   *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_path_FIG2DEV="$ac_dir/$ac_word"
@@ -1889,7 +2410,7 @@ fi
 # Extract the first word of "jade", so it can be a program name with args.
 set dummy jade; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1893: checking for $ac_word" >&5
+echo "configure:2414: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_JADE'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1897,13 +2418,9 @@ else
   /*)
   ac_cv_path_JADE="$JADE" # Let the user override the test with a path.
   ;;
-  ?:/*)                         
-  ac_cv_path_JADE="$JADE" # Let the user override the test with a dos path.
-  ;;
   *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_path_JADE="$ac_dir/$ac_word"
@@ -1925,7 +2442,7 @@ fi
 # Extract the first word of "jadetex", so it can be a program name with args.
 set dummy jadetex; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1929: checking for $ac_word" >&5
+echo "configure:2446: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_JADETEX'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1933,13 +2450,9 @@ else
   /*)
   ac_cv_path_JADETEX="$JADETEX" # Let the user override the test with a path.
   ;;
-  ?:/*)                         
-  ac_cv_path_JADETEX="$JADETEX" # Let the user override the test with a dos path.
-  ;;
   *)
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
-  ac_dummy="$PATH"
-  for ac_dir in $ac_dummy; do 
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
     test -z "$ac_dir" && ac_dir=.
     if test -f $ac_dir/$ac_word; then
       ac_cv_path_JADETEX="$ac_dir/$ac_word"
@@ -1959,9 +2472,6 @@ else
 fi
 
 
-
-
-
 trap '' 1 2 15
 cat > confcache <<\EOF
 # This file is a shell script that caches the results of configure
@@ -1985,7 +2495,7 @@ EOF
 # Ultrix sh set writes to stderr and can't be redirected directly,
 # and sets the high bit in the cache file unless we assign to the vars.
 (set) 2>&1 |
-  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  case `(ac_space=' '; set) 2>&1` in
   *ac_space=\ *)
     # `set' does not quote correctly, so add quotes (double-quote substitution
     # turns \\\\ into \\, and sed turns \\ into \).
@@ -2052,7 +2562,7 @@ do
     echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
     exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
   -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
-    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    echo "$CONFIG_STATUS generated by autoconf version 2.12"
     exit 0 ;;
   -help | --help | --hel | --he | --h)
     echo "\$ac_cs_usage"; exit 0 ;;
@@ -2063,7 +2573,7 @@ done
 ac_given_srcdir=$srcdir
 ac_given_INSTALL="$INSTALL"
 
-trap 'rm -fr `echo "Makefile src/Makefile check/Makefile ginsh/Makefile doc/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+trap 'rm -fr `echo "Makefile ginac/Makefile check/Makefile ginsh/Makefile doc/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
 EOF
 cat >> $CONFIG_STATUS <<EOF
 
@@ -2072,11 +2582,9 @@ sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
  s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
 $ac_vpsub
 $extrasub
-s%@SHELL@%$SHELL%g
 s%@CFLAGS@%$CFLAGS%g
 s%@CPPFLAGS@%$CPPFLAGS%g
 s%@CXXFLAGS@%$CXXFLAGS%g
-s%@FFLAGS@%$FFLAGS%g
 s%@DEFS@%$DEFS%g
 s%@LDFLAGS@%$LDFLAGS%g
 s%@LIBS@%$LIBS%g
@@ -2095,17 +2603,37 @@ s%@includedir@%$includedir%g
 s%@oldincludedir@%$oldincludedir%g
 s%@infodir@%$infodir%g
 s%@mandir@%$mandir%g
-s%@CXX@%$CXX%g
-s%@CXXCPP@%$CXXCPP%g
 s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
-s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
 s%@INSTALL_DATA@%$INSTALL_DATA%g
-s%@MAKEDEPEND@%$MAKEDEPEND%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@MAINT@%$MAINT%g
+s%@CXX@%$CXX%g
+s%@CXXCPP@%$CXXCPP%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@RANLIB@%$RANLIB%g
+s%@CC@%$CC%g
+s%@LD@%$LD%g
+s%@NM@%$NM%g
+s%@LN_S@%$LN_S%g
 s%@LIBTOOL@%$LIBTOOL%g
 s%@LEX@%$LEX%g
 s%@LEXLIB@%$LEXLIB%g
-s%@YACC@%$YACC%g
+s%@CPP@%$CPP%g
 s%@LEX_OUTPUT_ROOT@%$LEX_OUTPUT_ROOT%g
+s%@YACC@%$YACC%g
+s%@LIBOBJS@%$LIBOBJS%g
 s%@DOXYGEN@%$DOXYGEN%g
 s%@LATEX@%$LATEX%g
 s%@MAKEINDEX@%$MAKEINDEX%g
@@ -2113,8 +2641,6 @@ s%@DVIPS@%$DVIPS%g
 s%@FIG2DEV@%$FIG2DEV%g
 s%@JADE@%$JADE%g
 s%@JADETEX@%$JADETEX%g
-s%@shared@%$shared%g
-s%@LibGiNaC_Ver@%$LibGiNaC_Ver%g
 
 CEOF
 EOF
@@ -2156,7 +2682,7 @@ EOF
 
 cat >> $CONFIG_STATUS <<EOF
 
-CONFIG_FILES=\${CONFIG_FILES-"Makefile src/Makefile check/Makefile ginsh/Makefile doc/Makefile"}
+CONFIG_FILES=\${CONFIG_FILES-"Makefile ginac/Makefile check/Makefile ginsh/Makefile doc/Makefile"}
 EOF
 cat >> $CONFIG_STATUS <<\EOF
 for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
@@ -2325,8 +2851,10 @@ fi; done
 EOF
 cat >> $CONFIG_STATUS <<EOF
 
+
 EOF
 cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
 
 exit 0
 EOF
@@ -2334,4 +2862,4 @@ chmod +x $CONFIG_STATUS
 rm -fr confdefs* $ac_clean_files
 test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
 
-echo "now type make"
+echo "Configuration done. Now type \"make\"."
index 069bb7279c9f9cf8ca5e6a17a3d545b44b60d9b2..a846c91e0fe1974d6ecbbf08fefb2968a8574219 100644 (file)
@@ -1,82 +1,47 @@
-dnl ===========================================================================
-dnl Process this file with GNU Autoconf to produce a configure script. Then
-dnl call ./configure to create Makefiles. After that say make and make install.
-dnl See aclocal.m4 for additional self-made macros.
-dnl ===========================================================================
+dnl Process this file with autoconf to produce a configure script.
 
-dnl This file is used as a signal that everything is in place:
-AC_INIT(include/GiNaC/ginac.h)
-dnl A convenient header file for some additional system-dependend output:
-AC_CONFIG_HEADER(config.h)
+AC_INIT(ginac/basic.cpp)
+AM_CONFIG_HEADER(config.h)
+AC_PREREQ(2.12)
 
-dnl Set the Version Number at this place only:
-GiNaC_Major_Version=0
-GiNaC_Minor_Version=0
-GiNaC_Micro_Version=40
-dnl This composite variable can be inserted where it appears necessary:
-GiNaC_Version="${GiNaC_Major_Version}.${GiNaC_Minor_Version}.${GiNaC_Micro_Version}"
-dnl This composition is needed for libtool, if a shared lib shall be built:
-LibGiNaC_Ver="${GiNaC_Major_Version}:${GiNaC_Micro_Version}:${GiNaC_Minor_Version}"
-
-dnl ===========================================================================
-dnl Several features need to be added to standard-configure:
-dnl ===========================================================================
-AC_ARG_ENABLE(shared,
-    [  --enable-shared         build shared libraries [default=no]
-                          (a static library will still be built as well)],
-    shared=${enableval}, shared="no")
+dnl This defines PACKAGE and VERSION
+AM_INIT_AUTOMAKE([GiNaC], [0.4])
+AM_MAINTAINER_MODE
 
 dnl ===========================================================================
 dnl Check for the compiler and all the utilities needed for the build:
 dnl ===========================================================================
-dnl Which is the C++ Compiler? (whether to use c++, g++, gcc, CC, cxx, cc++...)
 AC_PROG_CXX
-dnl How to run the C++ preprocessor?
 AC_PROG_CXXCPP
+AM_PROG_INSTALL
+AM_PROG_LIBTOOL
+AM_PROG_LEX
+AC_PROG_YACC
+
 dnl Switch to C++ language mode for the following libraries and headers:
 AC_LANG_CPLUSPLUS
+
 dnl Make sure the following libraries work by testing for symbols therein. 
 dnl They are automatically added the the variable $LIBS and thus passed into
 dnl the Makefile:
 AC_CHECK_LIB(stdc++, cout)
+
 dnl Make sure all the necessary new-style headers are installed on the system.
 dnl If one of them cannot be found the system is probably not ANSI-conform
 dnl enough so trying the .h-style headers is a waste of time.
 AC_CHECK_HEADERS(iostream vector map string list typeinfo iterator strstream stdexcept algorithm, ,
     AC_MSG_ERROR(need to have ANSI compliant headers))
+
 dnl We need to have Bruno Haible's CLN installed (macros are in aclocal.m4):
 GINAC_CHECK_CLN_H
 GINAC_CHECK_LIBCLN
-dnl We need to distribure install-sh anyways since otherwise configure will
-dnl refuse to do several things, like divert into subdirs and so:
-AC_PROG_INSTALL
-dnl Todd Brunhoff's makedepend utility is needed by make:
-AC_PATH_PROG(MAKEDEPEND, makedepend, "")
-dnl We need GNU libtool if the user chose to create a shared lib. (By using a 
-dnl little trick we can safely recycle the variable shlib which is later passed
-dnl into the Makefile.)
-case "${shared}" in
-"yes"|"Yes"|"YES")      # Default-enable ("yes") or user was nitpicking:
-    shared="shlib";
-    AC_PATH_PROG(LIBTOOL, libtool, "")
-    if test "${LIBTOOL}" == ""; then
-        AC_MSG_WARN([libtool not found: building static lib only])
-        shared="";
-    fi
-    ;;
-*)      # Default, default-disable ("no") or user entered bogus:
-    shared="";
-    ;;
-esac
-dnl Check for helpers needed for building the GiNaC interactive shell (ginsh):
-AC_PROG_LEX
-AC_PROG_YACC
-AC_DECL_YYTEXT
-AC_HEADER_STDC
+
+dnl Check for stuff needed for building the GiNaC interactive shell (ginsh):
 AC_CHECK_HEADERS(unistd.h)
-AC_CHECK_FUNCS(strdup)
-AC_CHECK_HEADERS(readline/readline.h readline/history.h, , AC_MSG_ERROR(need to have GNU readline headers))
-AC_CHECK_LIB(readline, readline, , AC_MSG_ERROR(need to have GNU readline library))
+AC_REPLACE_FUNCS(strdup)
+AC_CHECK_HEADERS(readline/readline.h readline/history.h)
+AC_CHECK_LIB(readline, readline)
+
 dnl Check for utilities needed by the different kinds of documentation.
 dnl Documantation needs only be built when extending it, so never mind if it
 dnl cannot find those helpers:
@@ -88,14 +53,8 @@ AC_PATH_PROG(FIG2DEV, fig2dev, "")
 AC_PATH_PROG(JADE, jade, "")
 AC_PATH_PROG(JADETEX, jadetex, "")
 
-dnl ===========================================================================
-dnl Substitute these variables in the Makefile:
-dnl ===========================================================================
-AC_SUBST(shared)
-AC_SUBST(LibGiNaC_Ver)
-
 dnl ===========================================================================
 dnl Produce a Makefile from Makefile.in:
 dnl ===========================================================================
-AC_OUTPUT([Makefile src/Makefile check/Makefile ginsh/Makefile doc/Makefile])
-echo "now type make"
+AC_OUTPUT([Makefile ginac/Makefile check/Makefile ginsh/Makefile doc/Makefile])
+echo "Configuration done. Now type \"make\"."
diff --git a/doc/Makefile b/doc/Makefile
deleted file mode 100644 (file)
index 66acd0f..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-# Generated automatically from Makefile.in by configure.
-# This is the prototype Makefile for all of GiNaC's documentation.  It tries to
-# be tolerant---if some tools were not found it skips the built of that part
-# of documentation and tries to continue.
-
-# Substitution variables from configure skript:
-# Here come the usual install directories in GNU-configure fashion:
-prefix = /usr/local
-docdir = ${prefix}/share/doc/GiNaC
-srcdir = .
-# Dimitri van Heesch's Doxygen is needed for developer's resource:
-DOXYGEN = /usr/local/bin_i386/doxygen
-# LaTeX and friends are needed for processing developer's resource for print:
-LATEX = /usr/local/bin/latex
-MAKEINDEX = /usr/local/bin/makeindex
-DVIPS = /usr/local/bin/dvips
-FIG2DEV = /usr/bin/X11/fig2dev
-# Jade and friends needed for generating the tutorial:
-JADE = /usr/bin/jade
-JADETEX = /usr/local/bin/jadetex
-# Arguments for Jade and friends (does anybody know how to find them out?)
-# JADEARGS_TEX = -t tex -o tutorial.tex -d /usr/lib/dsssl/stylesheets/docbook/print/docbook.dsl
-JADEARGS_TEX = -t tex -o tutorial.tex -d /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl
-# JADEARGS_HTML = -t sgml -d /usr/lib/dsssl/stylesheets/docbook/html/docbook.dsl
-JADEARGS_HTML = -t sgml -d /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl
-# Autoconf macro AC_PROC_INSTALL sets these:
-INSTALL = /usr/bin/install -c
-INSTALL_DATA = ${INSTALL} -m 644
-# All LaTeX builds will take place in a separate subdirectory:
-VPATH = .:./latex:./tutorial
-
-# default target:
-all: reference tutorial
-
-# REFERENCE:
-# This section produces HTML'ed and TeX'ed developer's reference from the
-# sources with a JavaDoc-like tool (in this case doxygen):
-reference_html:
-       @ if [ ! -d ${srcdir}/reference ]; then mkdir ${srcdir}/reference; fi
-       @ if [ "${DOXYGEN}" ]; then \
-               echo "Running ${DOXYGEN} ./DoxyfileHTML..."; \
-               cd ..; ${DOXYGEN} ./doc/DoxyfileHTML; \
-       else \
-               echo "warning: target reference_html disabled by configuration"; \
-       fi
-
-reference.tex:
-       @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi
-       @ if [ "${DOXYGEN}" ]; then \
-               echo "Running ${DOXYGEN} ./DoxyfileTEX..."; \
-               cd ..; ${DOXYGEN} ./doc/DoxyfileTEX; \
-       else \
-               echo "warning: target reference.tex disabled by configuration"; \
-       fi
-       - mv ${srcdir}/latex/refman.tex ${srcdir}/latex/reference.tex 
-
-reference.dvi: reference.tex
-       @ if [ "${LATEX}" -a "${MAKEINDEX}" ]; then \
-               cd latex; \
-               ${LATEX} reference.tex && \
-               ${MAKEINDEX} reference.idx && \
-               ${LATEX} reference.tex; \
-       else \
-               echo "warning: target reference.dvi disabled by configuration"; \
-       fi
-
-reference.ps: reference.dvi
-       @ if [ "${DVIPS}" ]; then \
-               echo "Running ${DVIPS} -o reference.ps reference.dvi..."; \
-               cd latex; ${DVIPS} -o reference.ps reference.dvi; \
-       else \
-               echo "warning: target reference.ps disabled by configuration"; \
-       fi
-
-reference: reference_html reference.ps
-
-# TUTORIAL:
-# This section produces HTML'ed and TeX'ed versions of the tutorial using a
-# SGML to TeX converter (in this case jade).  As a dirty hack, we are doing
-# some regexpese to tutorial.sgml prior to parsing it, in order to allow for
-# different graphics output.  This seems to be an ugly limitation of docbook...
-
-EPS = classhierarchy.eps rep_naive.eps rep_pair.eps
-PNG = classhierarchy.png rep_naive.png rep_pair.png
-
-tutorial/index.html: tutorial.sgml.in ${PNG}
-       @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi
-       @ if [ "${JADE}" ]; then \
-               sed -e 's/graext/png/g' -e 's/GRAEXT/GIF/g' tutorial.sgml.in > tutorial.sgml; \
-               echo "Running ${JADE} ${JADEARGS_HTML} tutorial.sgml..."; \
-               cd tutorial/; ${JADE} ${JADEARGS_HTML} ../tutorial.sgml; \
-               if [ -f book1.html ]; then cp book1.html index.html; fi; \
-       else \
-               echo "warning: target tutorial_html disabled by configuration"; \
-       fi
-
-tutorial.tex: tutorial.sgml.in ${EPS}
-       @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi
-       @ if [ "${JADE}" -a "${LATEX}" ]; then \
-               sed -e 's/graext/eps/g' -e 's/GRAEXT/EPS/g' tutorial.sgml.in > tutorial.sgml; \
-               echo "Running ${JADE} ${JADEARGS_TEX} tutorial.sgml..."; \
-               cd latex; ${JADE} ${JADEARGS_TEX} ../tutorial.sgml ; \
-       else \
-               echo "warning: target tutorial.tex disabled by configuration"; \
-       fi
-
-tutorial.dvi: tutorial.tex
-       @ if [ "${JADETEX}" ]; then \
-               echo "Running ${JADETEX} tutorial.tex..."; \
-               cd latex; ${JADETEX} tutorial.tex && ${JADETEX} tutorial.tex && ${JADETEX} tutorial.tex; \
-       else \
-               echo "warning: target tutorial.dvi disabled by configuration"; \
-       fi
-
-tutorial.ps: tutorial.dvi
-       @ if [ "${DVIPS}" ]; then \
-               echo "Running ${DVIPS} tutorial.dvi -o tutorial.ps..."; \
-               cd latex; ${DVIPS} tutorial.dvi -o tutorial.ps; \
-       else \
-               echo "warning: target tutorial.ps disabled by configuration"; \
-       fi
-
-tutorial:      tutorial/index.html tutorial.ps
-
-# Target for installing all generated documentation files on the system.
-# (Foolproof: installs what we got, even if one or more targets failed.)
-install:
-       - ${INSTALL} -d ${docdir}/reference/
-       - ${INSTALL_DATA} ${srcdir}/reference/* ${docdir}/reference/
-       - ${INSTALL_DATA} ${srcdir}/latex/reference.ps ${docdir}/
-       - ${INSTALL} -d ${docdir}/tutorial/
-       - ${INSTALL_DATA} ${srcdir}/tutorial/* ${docdir}/tutorial/
-       - ${INSTALL_DATA} ${srcdir}/latex/tutorial.ps ${docdir}/
-
-# Removes all installed documentation files from the system:
-uninstall:
-       rm -rf ${docdir}
-
-# The next targets should only be called in case of emergency by developers, 
-# since the complete documentation is not normally rebuilt.  In any case, they
-# should only be called from people who know what they are doing and never 
-# from top-level Makefile's targets clean and distclean.
-clean:
-       rm -rf ${srcdir}/tutorial ${srcdir}/reference ${srcdir}/latex
-       rm -f tutorial.sgml
-
-distclean: clean
-       rm -f Makefile
-
-# Special dummy targets:
-.SUFFIXES: .fig .eps .png
-.PHONY: all clean distclean reference tutorial
-.SILENT: all reference tutorial_html tutorial_tex
-
-# Suffix rules:
-.fig.eps :
-       @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi
-       if [ "${FIG2DEV}" ]; then \
-               ${FIG2DEV} -L ps -m 0.8 $< ${srcdir}/latex/$@; \
-       else \
-               echo "warning: fig2dev was not found by configure"; \
-       fi
-.fig.png :
-       @ if [ ! -d ${srcdir}/tutorial ]; then mkdir ${srcdir}/tutorial; fi
-       if [ "${FIG2DEV}" ]; then \
-               ${FIG2DEV} -L png $< ${srcdir}/tutorial/$@; \
-       else \
-               echo "warning: fig2dev was not found by configure"; \
-       fi
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..96d7a6a
--- /dev/null
@@ -0,0 +1 @@
+## Process this file with automake to produce Makefile.in
index ebe33f6925aa6bb38810ed3ed123fd3de7678492..dad8d832f9c0535d2bbd81e9650f099fef829c98 100644 (file)
-# This is the prototype Makefile for all of GiNaC's documentation.  It tries to
-# be tolerant---if some tools were not found it skips the built of that part
-# of documentation and tries to continue.
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
 
-# Substitution variables from configure skript:
-# Here come the usual install directories in GNU-configure fashion:
-prefix = @prefix@
-docdir = @datadir@/doc/GiNaC
 srcdir = @srcdir@
-# Dimitri van Heesch's Doxygen is needed for developer's resource:
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CC = @CC@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
 DOXYGEN = @DOXYGEN@
-# LaTeX and friends are needed for processing developer's resource for print:
-LATEX = @LATEX@
-MAKEINDEX = @MAKEINDEX@
 DVIPS = @DVIPS@
 FIG2DEV = @FIG2DEV@
-# Jade and friends needed for generating the tutorial:
 JADE = @JADE@
 JADETEX = @JADETEX@
-# Arguments for Jade and friends (does anybody know how to find them out?)
-# JADEARGS_TEX = -t tex -o tutorial.tex -d /usr/lib/dsssl/stylesheets/docbook/print/docbook.dsl
-JADEARGS_TEX = -t tex -o tutorial.tex -d /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl
-# JADEARGS_HTML = -t sgml -d /usr/lib/dsssl/stylesheets/docbook/html/docbook.dsl
-JADEARGS_HTML = -t sgml -d /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl
-# Autoconf macro AC_PROC_INSTALL sets these:
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-# All LaTeX builds will take place in a separate subdirectory:
-VPATH = @srcdir@:@srcdir@/latex:@srcdir@/tutorial
-
-# default target:
-all: reference tutorial
-
-# REFERENCE:
-# This section produces HTML'ed and TeX'ed developer's reference from the
-# sources with a JavaDoc-like tool (in this case doxygen):
-reference_html:
-       @ if [ ! -d ${srcdir}/reference ]; then mkdir ${srcdir}/reference; fi
-       @ if [ "${DOXYGEN}" ]; then \
-               echo "Running ${DOXYGEN} ./DoxyfileHTML..."; \
-               cd ..; ${DOXYGEN} ./doc/DoxyfileHTML; \
-       else \
-               echo "warning: target reference_html disabled by configuration"; \
-       fi
-
-reference.tex:
-       @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi
-       @ if [ "${DOXYGEN}" ]; then \
-               echo "Running ${DOXYGEN} ./DoxyfileTEX..."; \
-               cd ..; ${DOXYGEN} ./doc/DoxyfileTEX; \
-       else \
-               echo "warning: target reference.tex disabled by configuration"; \
-       fi
-       - mv ${srcdir}/latex/refman.tex ${srcdir}/latex/reference.tex 
-
-reference.dvi: reference.tex
-       @ if [ "${LATEX}" -a "${MAKEINDEX}" ]; then \
-               cd latex; \
-               ${LATEX} reference.tex && \
-               ${MAKEINDEX} reference.idx && \
-               ${LATEX} reference.tex; \
-       else \
-               echo "warning: target reference.dvi disabled by configuration"; \
-       fi
-
-reference.ps: reference.dvi
-       @ if [ "${DVIPS}" ]; then \
-               echo "Running ${DVIPS} -o reference.ps reference.dvi..."; \
-               cd latex; ${DVIPS} -o reference.ps reference.dvi; \
-       else \
-               echo "warning: target reference.ps disabled by configuration"; \
-       fi
-
-reference: reference_html reference.ps
-
-# TUTORIAL:
-# This section produces HTML'ed and TeX'ed versions of the tutorial using a
-# SGML to TeX converter (in this case jade).  As a dirty hack, we are doing
-# some regexpese to tutorial.sgml prior to parsing it, in order to allow for
-# different graphics output.  This seems to be an ugly limitation of docbook...
-
-EPS = classhierarchy.eps rep_naive.eps rep_pair.eps
-PNG = classhierarchy.png rep_naive.png rep_pair.png
-
-tutorial/index.html: tutorial.sgml.in ${PNG}
-       @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi
-       @ if [ "${JADE}" ]; then \
-               sed -e 's/graext/png/g' -e 's/GRAEXT/GIF/g' tutorial.sgml.in > tutorial.sgml; \
-               echo "Running ${JADE} ${JADEARGS_HTML} tutorial.sgml..."; \
-               cd tutorial/; ${JADE} ${JADEARGS_HTML} ../tutorial.sgml; \
-               if [ -f book1.html ]; then cp book1.html index.html; fi; \
-       else \
-               echo "warning: target tutorial_html disabled by configuration"; \
-       fi
-
-tutorial.tex: tutorial.sgml.in ${EPS}
-       @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi
-       @ if [ "${JADE}" -a "${LATEX}" ]; then \
-               sed -e 's/graext/eps/g' -e 's/GRAEXT/EPS/g' tutorial.sgml.in > tutorial.sgml; \
-               echo "Running ${JADE} ${JADEARGS_TEX} tutorial.sgml..."; \
-               cd latex; ${JADE} ${JADEARGS_TEX} ../tutorial.sgml ; \
-       else \
-               echo "warning: target tutorial.tex disabled by configuration"; \
-       fi
-
-tutorial.dvi: tutorial.tex
-       @ if [ "${JADETEX}" ]; then \
-               echo "Running ${JADETEX} tutorial.tex..."; \
-               cd latex; ${JADETEX} tutorial.tex && ${JADETEX} tutorial.tex && ${JADETEX} tutorial.tex; \
-       else \
-               echo "warning: target tutorial.dvi disabled by configuration"; \
-       fi
-
-tutorial.ps: tutorial.dvi
-       @ if [ "${DVIPS}" ]; then \
-               echo "Running ${DVIPS} tutorial.dvi -o tutorial.ps..."; \
-               cd latex; ${DVIPS} tutorial.dvi -o tutorial.ps; \
-       else \
-               echo "warning: target tutorial.ps disabled by configuration"; \
-       fi
-
-tutorial:      tutorial/index.html tutorial.ps
-
-# Target for installing all generated documentation files on the system.
-# (Foolproof: installs what we got, even if one or more targets failed.)
-install:
-       - ${INSTALL} -d ${docdir}/reference/
-       - ${INSTALL_DATA} ${srcdir}/reference/* ${docdir}/reference/
-       - ${INSTALL_DATA} ${srcdir}/latex/reference.ps ${docdir}/
-       - ${INSTALL} -d ${docdir}/tutorial/
-       - ${INSTALL_DATA} ${srcdir}/tutorial/* ${docdir}/tutorial/
-       - ${INSTALL_DATA} ${srcdir}/latex/tutorial.ps ${docdir}/
-
-# Removes all installed documentation files from the system:
-uninstall:
-       rm -rf ${docdir}
-
-# The next targets should only be called in case of emergency by developers, 
-# since the complete documentation is not normally rebuilt.  In any case, they
-# should only be called from people who know what they are doing and never 
-# from top-level Makefile's targets clean and distclean.
-clean:
-       rm -rf ${srcdir}/tutorial ${srcdir}/reference ${srcdir}/latex
-       rm -f tutorial.sgml
-
-distclean: clean
-       rm -f Makefile
-
-# Special dummy targets:
-.SUFFIXES: .fig .eps .png
-.PHONY: all clean distclean reference tutorial
-.SILENT: all reference tutorial_html tutorial_tex
-
-# Suffix rules:
-.fig.eps :
-       @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi
-       if [ "${FIG2DEV}" ]; then \
-               ${FIG2DEV} -L ps -m 0.8 $< ${srcdir}/latex/$@; \
-       else \
-               echo "warning: fig2dev was not found by configure"; \
-       fi
-.fig.png :
-       @ if [ ! -d ${srcdir}/tutorial ]; then mkdir ${srcdir}/tutorial; fi
-       if [ "${FIG2DEV}" ]; then \
-               ${FIG2DEV} -L png $< ${srcdir}/tutorial/$@; \
-       else \
-               echo "warning: fig2dev was not found by configure"; \
-       fi
+LATEX = @LATEX@
+LD = @LD@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINDEX = @MAKEINDEX@
+MAKEINFO = @MAKEINFO@
+NM = @NM@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = doc
+
+distdir: $(DISTFILES)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(top_distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu doc/Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ginac/Makefile.am b/ginac/Makefile.am
new file mode 100644 (file)
index 0000000..d215d8c
--- /dev/null
@@ -0,0 +1,16 @@
+## Process this file with automake to produce Makefile.in
+lib_LTLIBRARIES = libginac.la
+libginac_la_SOURCES = add.cpp basic.cpp constant.cpp diff.cpp ex.cpp \
+  expairseq.cpp exprseq.cpp fail.cpp function.cpp inifcns.cpp \
+  inifcns_trans.cpp inifcns_gamma.cpp matrix.cpp mul.cpp normal.cpp \
+  numeric.cpp operators.cpp power.cpp print.cpp printraw.cpp printtree.cpp \
+  printcsrc.cpp relational.cpp symbol.cpp utils.cpp series.cpp ncmul.cpp \
+  clifford.cpp structure.cpp color.cpp indexed.cpp idx.cpp isospin.cpp \
+  exprseq_suppl.cpp lst.cpp lst_suppl.cpp simp_lor.cpp coloridx.cpp \
+  lorentzidx.cpp utils.h
+ginacincludedir = $(includedir)/ginac
+ginacinclude_HEADERS = ginac.h add.h basic.h clifford.h color.h coloridx.h \
+  constant.h debugmsg.h ex.h expair.h expairseq.h exprseq.h fail.h flags.h \
+  function.h idx.h indexed.h inifcns.h isospin.h lorentzidx.h lst.h matrix.h \
+  mul.h ncmul.h normal.h numeric.h operators.h power.h relational.h series.h \
+  simp_lor.h structure.h symbol.h tinfos.h
diff --git a/ginac/Makefile.in b/ginac/Makefile.in
new file mode 100644 (file)
index 0000000..724c971
--- /dev/null
@@ -0,0 +1,383 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CC = @CC@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+DOXYGEN = @DOXYGEN@
+DVIPS = @DVIPS@
+FIG2DEV = @FIG2DEV@
+JADE = @JADE@
+JADETEX = @JADETEX@
+LATEX = @LATEX@
+LD = @LD@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINDEX = @MAKEINDEX@
+MAKEINFO = @MAKEINFO@
+NM = @NM@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+
+lib_LTLIBRARIES = libginac.la
+libginac_la_SOURCES = add.cpp basic.cpp constant.cpp diff.cpp ex.cpp \
+  expairseq.cpp exprseq.cpp fail.cpp function.cpp inifcns.cpp \
+  inifcns_trans.cpp inifcns_gamma.cpp matrix.cpp mul.cpp normal.cpp \
+  numeric.cpp operators.cpp power.cpp print.cpp printraw.cpp printtree.cpp \
+  printcsrc.cpp relational.cpp symbol.cpp utils.cpp series.cpp ncmul.cpp \
+  clifford.cpp structure.cpp color.cpp indexed.cpp idx.cpp isospin.cpp \
+  exprseq_suppl.cpp lst.cpp lst_suppl.cpp simp_lor.cpp coloridx.cpp \
+  lorentzidx.cpp utils.h
+ginacincludedir = $(includedir)/ginac
+ginacinclude_HEADERS = ginac.h add.h basic.h clifford.h color.h coloridx.h \
+  constant.h debugmsg.h ex.h expair.h expairseq.h exprseq.h fail.h flags.h \
+  function.h idx.h indexed.h inifcns.h isospin.h lorentzidx.h lst.h matrix.h \
+  mul.h ncmul.h normal.h numeric.h operators.h power.h relational.h series.h \
+  simp_lor.h structure.h symbol.h tinfos.h
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+LTLIBRARIES =  $(lib_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libginac_la_LDFLAGS = 
+libginac_la_LIBADD = 
+libginac_la_OBJECTS =  add.lo basic.lo constant.lo diff.lo ex.lo \
+expairseq.lo exprseq.lo fail.lo function.lo inifcns.lo inifcns_trans.lo \
+inifcns_gamma.lo matrix.lo mul.lo normal.lo numeric.lo operators.lo \
+power.lo print.lo printraw.lo printtree.lo printcsrc.lo relational.lo \
+symbol.lo utils.lo series.lo ncmul.lo clifford.lo structure.lo color.lo \
+indexed.lo idx.lo isospin.lo exprseq_suppl.lo lst.lo lst_suppl.lo \
+simp_lor.lo coloridx.lo lorentzidx.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+CXXLINK = $(LIBTOOL) --mode=link $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@
+HEADERS =  $(ginacinclude_HEADERS)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+DEP_FILES =  .deps/add.P .deps/basic.P .deps/clifford.P .deps/color.P \
+.deps/coloridx.P .deps/constant.P .deps/diff.P .deps/ex.P \
+.deps/expairseq.P .deps/exprseq.P .deps/exprseq_suppl.P .deps/fail.P \
+.deps/function.P .deps/idx.P .deps/indexed.P .deps/inifcns.P \
+.deps/inifcns_gamma.P .deps/inifcns_trans.P .deps/isospin.P \
+.deps/lorentzidx.P .deps/lst.P .deps/lst_suppl.P .deps/matrix.P \
+.deps/mul.P .deps/ncmul.P .deps/normal.P .deps/numeric.P \
+.deps/operators.P .deps/power.P .deps/print.P .deps/printcsrc.P \
+.deps/printraw.P .deps/printtree.P .deps/relational.P .deps/series.P \
+.deps/simp_lor.P .deps/structure.P .deps/symbol.P .deps/utils.P
+CXXMKDEP = $(CXX) -M $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+SOURCES = $(libginac_la_SOURCES)
+OBJECTS = $(libginac_la_OBJECTS)
+
+all: Makefile $(LTLIBRARIES) $(HEADERS)
+
+.SUFFIXES:
+.SUFFIXES: .S .c .cpp .lo .o .s
+$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu ginac/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-libLTLIBRARIES:
+
+clean-libLTLIBRARIES:
+       -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+
+distclean-libLTLIBRARIES:
+
+maintainer-clean-libLTLIBRARIES:
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(libdir)
+       @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo "$(LIBTOOL)  --mode=install $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p"; \
+           $(LIBTOOL)  --mode=install $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p; \
+         else :; fi; \
+       done
+
+uninstall-libLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         $(LIBTOOL)  --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
+       done
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libginac.la: $(libginac_la_OBJECTS) $(libginac_la_DEPENDENCIES)
+       $(CXXLINK) -rpath $(libdir) $(libginac_la_LDFLAGS) $(libginac_la_OBJECTS) $(libginac_la_LIBADD) $(LIBS)
+.cpp.o:
+       $(CXXCOMPILE) -c $<
+.cpp.lo:
+       $(LTCXXCOMPILE) -c $<
+
+install-ginacincludeHEADERS: $(ginacinclude_HEADERS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(ginacincludedir)
+       @list='$(ginacinclude_HEADERS)'; for p in $$list; do \
+         if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
+         echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(ginacincludedir)/$$p"; \
+         $(INSTALL_DATA) $$d$$p $(DESTDIR)$(ginacincludedir)/$$p; \
+       done
+
+uninstall-ginacincludeHEADERS:
+       @$(NORMAL_UNINSTALL)
+       list='$(ginacinclude_HEADERS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(ginacincludedir)/$$p; \
+       done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = ginac
+
+distdir: $(DISTFILES)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(top_distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu ginac/Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+
+maintainer-clean-depend:
+       -rm -rf .deps
+
+%.o: %.c
+       @echo '$(COMPILE) -c $<'; \
+       $(COMPILE) -Wp,-MD,.deps/$(*F).P -c $<
+
+%.lo: %.c
+       @echo '$(LTCOMPILE) -c $<'; \
+       $(LTCOMPILE) -Wp,-MD,.deps/$(*F).p -c $<
+       @-sed -e 's/^\([^:]*\)\.o:/\1.lo \1.o:/' \
+         < .deps/$(*F).p > .deps/$(*F).P
+       @-rm -f .deps/$(*F).p
+
+%.o: %.cpp
+       @echo '$(CXXCOMPILE) -c $<'; \
+       $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).P -c $<
+
+%.lo: %.cpp
+       @echo '$(LTCXXCOMPILE) -c $<'; \
+       $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).p -c $<
+       @-sed -e 's/^\([^:]*\)\.o:/\1.lo \1.o:/' \
+         < .deps/$(*F).p > .deps/$(*F).P
+       @-rm -f .deps/$(*F).p
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: install-libLTLIBRARIES
+       @$(NORMAL_INSTALL)
+
+install-data: install-ginacincludeHEADERS
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: uninstall-libLTLIBRARIES uninstall-ginacincludeHEADERS
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+       $(mkinstalldirs)  $(DATADIR)$(libdir) $(DATADIR)$(ginacincludedir)
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-libLTLIBRARIES mostlyclean-compile \
+               mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+               mostlyclean-generic
+
+clean:  clean-libLTLIBRARIES clean-compile clean-libtool clean-tags \
+               clean-depend clean-generic mostlyclean
+
+distclean:  distclean-libLTLIBRARIES distclean-compile distclean-libtool \
+               distclean-tags distclean-depend distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-libLTLIBRARIES \
+               maintainer-clean-compile maintainer-clean-libtool \
+               maintainer-clean-tags maintainer-clean-depend \
+               maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \
+clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \
+uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \
+distclean-compile clean-compile maintainer-clean-compile \
+mostlyclean-libtool distclean-libtool clean-libtool \
+maintainer-clean-libtool uninstall-ginacincludeHEADERS \
+install-ginacincludeHEADERS tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir mostlyclean-depend \
+distclean-depend clean-depend maintainer-clean-depend info dvi \
+installcheck install-exec install-data install uninstall all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ginac/add.cpp b/ginac/add.cpp
new file mode 100644 (file)
index 0000000..0d88e32
--- /dev/null
@@ -0,0 +1,635 @@
+/** @file add.cpp
+ *
+ *  Implementation of GiNaC's sums of expressions. */
+
+#include <iostream>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+add::add()
+{
+    debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_ADD;
+}
+
+add::~add()
+{
+    debugmsg("add destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+add::add(add const & other)
+{
+    debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+add const & add::operator=(add const & other)
+{
+    debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void add::copy(add const & other)
+{
+    expairseq::copy(other);
+}
+
+void add::destroy(bool call_parent)
+{
+    if (call_parent) expairseq::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+add::add(ex const & lh, ex const & rh)
+{
+    debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_ADD;
+    overall_coeff=exZERO();
+    construct_from_2_ex(lh,rh);
+    ASSERT(is_canonical());
+}
+
+add::add(exvector const & v)
+{
+    debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_ADD;
+    overall_coeff=exZERO();
+    construct_from_exvector(v);
+    ASSERT(is_canonical());
+}
+
+/*
+add::add(epvector const & v, bool do_not_canonicalize)
+{
+    debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_ADD;
+    if (do_not_canonicalize) {
+        seq=v;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+        combine_same_terms(); // to build hashtab
+#endif // def EXPAIRSEQ_USE_HASHTAB
+    } else {
+        construct_from_epvector(v);
+    }
+    ASSERT(is_canonical());
+}
+*/
+
+add::add(epvector const & v)
+{
+    debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_ADD;
+    overall_coeff=exZERO();
+    construct_from_epvector(v);
+    ASSERT(is_canonical());
+}
+
+add::add(epvector const & v, ex const & oc)
+{
+    debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_ADD;
+    overall_coeff=oc;
+    construct_from_epvector(v);
+    ASSERT(is_canonical());
+}
+
+add::add(epvector * vp, ex const & oc)
+{
+    debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_ADD;
+    ASSERT(vp!=0);
+    overall_coeff=oc;
+    construct_from_epvector(*vp);
+    delete vp;
+    ASSERT(is_canonical());
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * add::duplicate() const
+{
+    debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
+    return new add(*this);
+}
+
+bool add::info(unsigned inf) const
+{
+    // TODO: optimize
+    if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
+        for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+            if (!(recombine_pair_to_ex(*it).info(inf)))
+                return false;
+        }
+        return true;
+    } else {
+        return expairseq::info(inf);
+    }
+}
+
+int add::degree(symbol const & s) const
+{
+    int deg=INT_MIN;
+    if (!overall_coeff.is_equal(exZERO())) {
+        deg=0;
+    }
+    int cur_deg;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        cur_deg=(*cit).rest.degree(s);
+        if (cur_deg>deg) deg=cur_deg;
+    }
+    return deg;
+}
+
+int add::ldegree(symbol const & s) const
+{
+    int deg=INT_MAX;
+    if (!overall_coeff.is_equal(exZERO())) {
+        deg=0;
+    }
+    int cur_deg;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        cur_deg=(*cit).rest.ldegree(s);
+        if (cur_deg<deg) deg=cur_deg;
+    }
+    return deg;
+}
+
+ex add::coeff(symbol const & s, int const n) const
+{
+    epvector coeffseq;
+    coeffseq.reserve(seq.size());
+
+    epvector::const_iterator it=seq.begin();
+    while (it!=seq.end()) {
+        coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
+                                                         (*it).coeff));
+        ++it;
+    }
+    if (n==0) {
+        return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
+    }
+    return (new add(coeffseq))->setflag(status_flags::dynallocated);
+}
+
+/*
+ex add::eval(int level) const
+{
+    // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
+    //                  +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
+    //                  +(...,x,0) -> +(...,x)
+    //                  +(x) -> x
+    //                  +() -> 0
+
+    debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
+
+    epvector newseq=seq;
+    epvector::iterator it1,it2;
+    
+    // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
+    it2=newseq.end()-1;
+    it1=it2-1;
+    while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
+                               is_exactly_of_type(*(*it2).rest.bp,numeric)) {
+        *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
+                    .add(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
+        newseq.pop_back();
+        it2=newseq.end()-1;
+        it1=it2-1;
+    }
+
+    if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
+        // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
+        *it2=expair(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff)),exONE());
+        // +(...,x,0) -> +(...,x)
+        if (ex_to_numeric((*it2).rest).compare(0)==0) {
+            newseq.pop_back();
+        }
+    }
+
+    if (newseq.size()==0) {
+        // +() -> 0
+        return exZERO();
+    } else if (newseq.size()==1) {
+        // +(x) -> x
+        return recombine_pair_to_ex(*(newseq.begin()));
+    }
+
+    return (new add(newseq,1))->setflag(status_flags::dynallocated  |
+                                        status_flags::evaluated );
+}
+*/
+
+/*
+ex add::eval(int level) const
+{
+    // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
+    //                  +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
+    //                  +(...,x,0) -> +(...,x)
+    //                  +(x) -> x
+    //                  +() -> 0
+
+    debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
+
+    if ((level==1)&&(flags & status_flags::evaluated)) {
+#ifdef DOASSERT
+        for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+            ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
+            ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
+                     (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
+        }
+#endif // def DOASSERT
+        return *this;
+    }
+
+    epvector newseq;
+    epvector::iterator it1,it2;
+    bool seq_copied=false;
+
+    epvector * evaled_seqp=evalchildren(level);
+    if (evaled_seqp!=0) {
+        // do more evaluation later
+        return (new add(evaled_seqp))->setflag(status_flags::dynallocated);
+    }
+
+#ifdef DOASSERT
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
+        ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
+                 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
+    }
+#endif // def DOASSERT
+
+    if (flags & status_flags::evaluated) {
+        return *this;
+    }
+    
+    expair const & last_expair=*(seq.end()-1);
+    expair const & next_to_last_expair=*(seq.end()-2);
+    int seq_size = seq.size();
+
+    // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
+    if ((!seq_copied)&&(seq_size>=2)&&
+        is_ex_exactly_of_type(last_expair.rest,numeric)&&
+        is_ex_exactly_of_type(next_to_last_expair.rest,numeric)) {
+        newseq=seq;
+        seq_copied=true;
+        it2=newseq.end()-1;
+        it1=it2-1;
+    }
+    while (seq_copied&&(newseq.size()>=2)&&
+           is_ex_exactly_of_type((*it1).rest,numeric)&&
+           is_ex_exactly_of_type((*it2).rest,numeric)) {
+        *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
+                    .add_dyn(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
+        newseq.pop_back();
+        it2=newseq.end()-1;
+        it1=it2-1;
+    }
+
+    // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
+    if ((!seq_copied)&&(seq_size>=1)&&
+        (is_ex_exactly_of_type(last_expair.rest,numeric))&&
+        (ex_to_numeric(last_expair.coeff).compare(numONE())!=0)) {
+        newseq=seq;
+        seq_copied=true;
+        it2=newseq.end()-1;
+    }
+    if (seq_copied&&(newseq.size()>=1)&&
+        (is_ex_exactly_of_type((*it2).rest,numeric))&&
+        (ex_to_numeric((*it2).coeff).compare(numONE())!=0)) {
+        *it2=expair(ex_to_numeric((*it2).rest).mul_dyn(ex_to_numeric((*it2).coeff)),exONE());
+    }
+        
+    // +(...,x,0) -> +(...,x)
+    if ((!seq_copied)&&(seq_size>=1)&&
+        (is_ex_exactly_of_type(last_expair.rest,numeric))&&
+        (ex_to_numeric(last_expair.rest).is_zero())) {
+        newseq=seq;
+        seq_copied=true;
+        it2=newseq.end()-1;
+    }
+    if (seq_copied&&(newseq.size()>=1)&&
+        (is_ex_exactly_of_type((*it2).rest,numeric))&&
+        (ex_to_numeric((*it2).rest).is_zero())) {
+        newseq.pop_back();
+    }
+
+    // +() -> 0
+    if ((!seq_copied)&&(seq_size==0)) {
+        return exZERO();
+    } else if (seq_copied&&(newseq.size()==0)) {
+        return exZERO();
+    }
+
+    // +(x) -> x
+    if ((!seq_copied)&&(seq_size==1)) {
+        return recombine_pair_to_ex(*(seq.begin()));
+    } else if (seq_copied&&(newseq.size()==1)) {
+        return recombine_pair_to_ex(*(newseq.begin()));
+    }
+
+    if (!seq_copied) return this->hold();
+
+    return (new add(newseq,1))->setflag(status_flags::dynallocated  |
+                                        status_flags::evaluated );
+}
+*/
+
+ex add::eval(int level) const
+{
+    // simplifications: +(;c) -> c
+    //                  +(x;1) -> x
+
+    debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
+
+    epvector * evaled_seqp=evalchildren(level);
+    if (evaled_seqp!=0) {
+        // do more evaluation later
+        return (new add(evaled_seqp,overall_coeff))->
+                   setflag(status_flags::dynallocated);
+    }
+
+#ifdef DOASSERT
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
+        if (is_ex_exactly_of_type((*cit).rest,numeric)) {
+            dbgprint();
+        }
+        ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
+    }
+#endif // def DOASSERT
+
+    if (flags & status_flags::evaluated) {
+        ASSERT(seq.size()>0);
+        ASSERT((seq.size()>1)||!overall_coeff.is_equal(exZERO()));
+        return *this;
+    }
+
+    int seq_size=seq.size();
+    if (seq_size==0) {
+        // +(;c) -> c
+        return overall_coeff;
+    } else if ((seq_size==1)&&overall_coeff.is_equal(exZERO())) {
+        // +(x;0) -> x
+        return recombine_pair_to_ex(*(seq.begin()));
+    }
+    return this->hold();
+}
+
+exvector add::get_indices(void) const
+{
+    // all terms in the sum should have the same indices (compatible tensors)
+    // however this is not checked, since there is no function yet which
+    // compares indices (idxvector can be unsorted) !!!!!!!!!!!
+    if (seq.size()==0) {
+        return exvector();
+    }
+    return (seq.begin())->rest.get_indices();
+}    
+
+ex add::simplify_ncmul(exvector const & v) const
+{
+    if (seq.size()==0) {
+        return expairseq::simplify_ncmul(v);
+    }
+    return (*seq.begin()).rest.simplify_ncmul(v);
+}    
+
+// protected
+
+int add::compare_same_type(basic const & other) const
+{
+    return expairseq::compare_same_type(other);
+}
+
+bool add::is_equal_same_type(basic const & other) const
+{
+    return expairseq::is_equal_same_type(other);
+}
+
+unsigned add::return_type(void) const
+{
+    if (seq.size()==0) {
+        return return_types::commutative;
+    }
+    return (*seq.begin()).rest.return_type();
+}
+   
+unsigned add::return_type_tinfo(void) const
+{
+    if (seq.size()==0) {
+        return tinfo_key;
+    }
+    return (*seq.begin()).rest.return_type_tinfo();
+}
+
+ex add::thisexpairseq(epvector const & v, ex const & oc) const
+{
+    return (new add(v,oc))->setflag(status_flags::dynallocated);
+}
+
+ex add::thisexpairseq(epvector * vp, ex const & oc) const
+{
+    return (new add(vp,oc))->setflag(status_flags::dynallocated);
+}
+
+/*
+expair add::split_ex_to_pair(ex const & e) const
+{
+    if (is_ex_exactly_of_type(e,mul)) {
+        mul const & mulref=ex_to_mul(e);
+        ASSERT(mulref.seq.size()>1);
+        ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
+        ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
+        if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
+            ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
+            epvector s=mulref.seq;
+            //s.pop_back();
+            //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
+            //              lastfactor);
+            mul * mulp=static_cast<mul *>(mulref.duplicate());
+#ifdef EXPAIRSEQ_USE_HASHTAB
+            mulp->remove_hashtab_entry(mulp->seq.end()-1);
+#endif // def EXPAIRSEQ_USE_HASHTAB
+            mulp->seq.pop_back();
+#ifdef EXPAIRSEQ_USE_HASHTAB
+            mulp->shrink_hashtab();
+#endif // def EXPAIRSEQ_USE_HASHTAB
+            mulp->clearflag(status_flags::evaluated);
+            mulp->clearflag(status_flags::hash_calculated);
+            return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
+        }
+    }
+    return expair(e,exONE());
+}
+*/
+
+expair add::split_ex_to_pair(ex const & e) const
+{
+    if (is_ex_exactly_of_type(e,mul)) {
+        mul const & mulref=ex_to_mul(e);
+        ex numfactor=mulref.overall_coeff;
+        // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
+        mul * mulcopyp=new mul(mulref);
+        mulcopyp->overall_coeff=exONE();
+        mulcopyp->clearflag(status_flags::evaluated);
+        mulcopyp->clearflag(status_flags::hash_calculated);
+        return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
+    }
+    return expair(e,exONE());
+}
+
+/*
+expair add::combine_ex_with_coeff_to_pair(ex const & e,
+                                          ex const & c) const
+{
+    ASSERT(is_ex_exactly_of_type(c,numeric));
+    if (is_ex_exactly_of_type(e,mul)) {
+        mul const & mulref=ex_to_mul(e);
+        ASSERT(mulref.seq.size()>1);
+        ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
+        ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
+        if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
+            ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
+            //epvector s=mulref.seq;
+            //s.pop_back();
+            //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
+            //              ex_to_numeric(lastfactor).mul_dyn(ex_to_numeric(c)));
+            mul * mulp=static_cast<mul *>(mulref.duplicate());
+#ifdef EXPAIRSEQ_USE_HASHTAB
+            mulp->remove_hashtab_entry(mulp->seq.end()-1);
+#endif // def EXPAIRSEQ_USE_HASHTAB
+            mulp->seq.pop_back();
+#ifdef EXPAIRSEQ_USE_HASHTAB
+            mulp->shrink_hashtab();
+#endif // def EXPAIRSEQ_USE_HASHTAB
+            mulp->clearflag(status_flags::evaluated);
+            mulp->clearflag(status_flags::hash_calculated);
+            if (are_ex_trivially_equal(c,exONE())) {
+                return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
+            } else if (are_ex_trivially_equal(lastfactor_rest,exONE())) {
+                return expair(mulp->setflag(status_flags::dynallocated),c);
+            }                
+            return expair(mulp->setflag(status_flags::dynallocated),
+                          ex_to_numeric(lastfactor_rest).mul_dyn(ex_to_numeric(c)));
+        }
+    }
+    return expair(e,c);
+}
+*/
+
+expair add::combine_ex_with_coeff_to_pair(ex const & e,
+                                          ex const & c) const
+{
+    ASSERT(is_ex_exactly_of_type(c,numeric));
+    if (is_ex_exactly_of_type(e,mul)) {
+        mul const & mulref=ex_to_mul(e);
+        ex numfactor=mulref.overall_coeff;
+        //mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
+        mul * mulcopyp=new mul(mulref);
+        mulcopyp->overall_coeff=exONE();
+        mulcopyp->clearflag(status_flags::evaluated);
+        mulcopyp->clearflag(status_flags::hash_calculated);
+        if (are_ex_trivially_equal(c,exONE())) {
+            return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
+        } else if (are_ex_trivially_equal(numfactor,exONE())) {
+            return expair(mulcopyp->setflag(status_flags::dynallocated),c);
+        }
+        return expair(mulcopyp->setflag(status_flags::dynallocated),
+                          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,exONE())) {
+            return expair(e,exONE());
+        }
+        return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),exONE());
+    }
+    return expair(e,c);
+}
+    
+expair add::combine_pair_with_coeff_to_pair(expair const & p,
+                                            ex const & c) const
+{
+    ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
+    ASSERT(is_ex_exactly_of_type(c,numeric));
+
+    if (is_ex_exactly_of_type(p.rest,numeric)) {
+        ASSERT(ex_to_numeric(p.coeff).is_equal(numONE())); // should be normalized
+        return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),exONE());
+    }
+
+    return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
+}
+    
+ex add::recombine_pair_to_ex(expair const & p) const
+{
+    //if (p.coeff.compare(exONE())==0) {
+    //if (are_ex_trivially_equal(p.coeff,exONE())) {
+    if (ex_to_numeric(p.coeff).is_equal(numONE())) {
+        return p.rest;
+    } else {
+        return p.rest*p.coeff;
+    }
+}
+
+ex add::expand(unsigned options) const
+{
+    epvector * vp=expandchildren(options);
+    if (vp==0) {
+        return *this;
+    }
+    return (new add(vp,overall_coeff))->setflag(status_flags::expanded    |
+                                                status_flags::dynallocated );
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// none
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned add::precedence=40;
+
+//////////
+// global constants
+//////////
+
+const add some_add;
+type_info const & typeid_add=typeid(some_add);
+
+
+
diff --git a/ginac/add.h b/ginac/add.h
new file mode 100644 (file)
index 0000000..6986b1e
--- /dev/null
@@ -0,0 +1,94 @@
+/** @file add.h
+ *
+ *  Interface to GiNaC's sums of expressions. */
+
+#ifndef _ADD_H_
+#define _ADD_H_
+
+#include "expairseq.h"
+
+/** Sum of expressions. */
+class add : public expairseq
+{
+    friend class mul;
+    friend class ncmul;
+    friend class power;
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    add();
+    ~add();
+    add(add const & other);
+    add const & operator=(add const & other);
+protected:
+    void copy(add const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    add(ex const & lh, ex const & rh);
+    add(exvector const & v);
+    add(epvector const & v);
+    //add(epvector const & v, bool do_not_canonicalize=0);
+    add(epvector const & v, ex const & oc);
+    add(epvector * vp, ex const & oc);
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+    int degree(symbol const & s) const;
+    int ldegree(symbol const & s) const;
+    ex coeff(symbol const & s, int const n=1) const;
+    ex eval(int level=0) const;
+    ex diff(symbol const & s) const;
+    ex series(symbol const & s, ex const & point, int order) const;
+    ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+    numeric integer_content(void) const;
+    ex smod(numeric const &xi) const;
+    numeric max_coefficient(void) const;
+    exvector get_indices(void) const;
+    ex simplify_ncmul(exvector const & v) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    ex thisexpairseq(epvector const & v, ex const & oc) const;
+    ex thisexpairseq(epvector * vp, ex const & oc) const;
+    void printpair(ostream & os, expair const & p,
+                   unsigned upper_precedence) const;
+    expair split_ex_to_pair(ex const & e) const;
+    expair combine_ex_with_coeff_to_pair(ex const & e,
+                                         ex const & c) const;
+    expair combine_pair_with_coeff_to_pair(expair const & p,
+                                           ex const & c) const;
+    ex recombine_pair_to_ex(expair const & p) const;
+    ex expand(unsigned options=0) const;
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+    // none
+
+// member variables
+
+protected:
+    static unsigned precedence;
+};
+
+// global constants
+
+extern const add some_add;
+extern type_info const & typeid_add;
+
+#define ex_to_add(X) static_cast<add const &>(*(X).bp)
+
+#endif // ndef _ADD_H_
+
diff --git a/ginac/basic.cpp b/ginac/basic.cpp
new file mode 100644 (file)
index 0000000..875bf75
--- /dev/null
@@ -0,0 +1,391 @@
+/** @file basic.cpp
+ *
+ *  Implementation of GiNaC's ABC. */
+
+#include <iostream>
+#include <typeinfo>
+#include <stdexcept>
+
+#include "ginac.h"
+#include "utils.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+#ifndef INLINE_BASIC_CONSTRUCTORS
+basic::basic() : flags(0), refcount(0), tinfo_key(TINFO_BASIC)
+{
+    debugmsg("basic default constructor",LOGLEVEL_CONSTRUCT);
+    // nothing to do
+}
+
+basic::~basic() 
+{
+    debugmsg("basic destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+    ASSERT((!(flags & status_flags::dynallocated))||(refcount==0));
+}
+
+basic::basic(basic const & other) : flags(0), refcount(0), tinfo_key(TINFO_BASIC)
+{
+    debugmsg("basic copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+#endif
+
+basic const & basic::operator=(basic const & other)
+{
+    debugmsg("basic operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+#if 0
+void basic::copy(basic const & other)
+{
+    flags=other.flags & ~ status_flags::dynallocated;
+    hashvalue=other.hashvalue;
+    tinfo_key=other.tinfo_key;
+}
+#endif
+
+//////////
+// other constructors
+//////////
+
+#ifndef INLINE_BASIC_CONSTRUCTORS
+basic::basic(unsigned ti) : flags(0), refcount(0), tinfo_key(ti)
+{
+    debugmsg("basic constructor with tinfo_key",LOGLEVEL_CONSTRUCT);
+    // nothing to do
+}
+#endif
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// none
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// public
+
+basic * basic::duplicate() const
+{
+    debugmsg("basic duplicate",LOGLEVEL_DUPLICATE);
+    return new basic(*this);
+}
+
+bool basic::info(unsigned inf) const
+{
+    return false; // all possible properties are false for basic objects
+}
+
+int basic::nops() const
+{
+    return 0;
+}
+
+ex basic::op(int const i) const
+{
+    return (const_cast<basic *>(this))->let_op(i);
+}
+
+ex & basic::let_op(int const i)
+{
+    throw(std::out_of_range("op() out of range"));
+}
+
+ex basic::operator[](ex const & index) const
+{
+    if (is_exactly_of_type(*index.bp,numeric)) {
+        return op(static_cast<numeric const &>(*index.bp).to_int());
+    }
+    throw(std::invalid_argument("non-numeric indices not supported by this type"));
+}
+
+ex basic::operator[](int const i) const
+{
+    return op(i);
+}
+
+bool basic::has(ex const & other) const
+{
+    ASSERT(other.bp!=0);
+    if (is_equal(*other.bp)) return true;
+    if (nops()>0) {
+        for (int i=0; i<nops(); i++) {
+            if (op(i).has(other)) return true;
+        }
+    }
+    return false;
+}
+
+int basic::degree(symbol const & s) const
+{
+    return 0;
+}
+
+int basic::ldegree(symbol const & s) const
+{
+    return 0;
+}
+
+ex basic::coeff(symbol const & s, int const n) const
+{
+    return n==0 ? *this : exZERO();
+}
+
+ex basic::collect(symbol const & s) const
+{
+    ex x;
+    int ldeg=ldegree(s);
+    int deg=degree(s);
+    for (int n=ldeg; n<=deg; n++) {
+        x += coeff(s,n)*power(s,n);
+    }
+    return x;
+}
+
+ex basic::eval(int level) const
+{
+    return this->hold();
+}
+
+ex basic::evalf(int level) const
+{
+    return *this;
+}
+
+ex basic::subs(lst const & ls, lst const & lr) const
+{
+    return *this;
+}
+
+exvector basic::get_indices(void) const
+{
+    return exvector(); // return an empty exvector
+}
+
+ex basic::simplify_ncmul(exvector const & v) const
+{
+    return simplified_ncmul(v);
+}
+
+// protected
+
+int basic::compare_same_type(basic const & other) const
+{
+    return compare_pointers(this, &other);
+}
+
+bool basic::is_equal_same_type(basic const & other) const
+{
+    return compare_same_type(other)==0;
+}
+
+unsigned basic::return_type(void) const
+{
+    return return_types::commutative;
+}
+
+unsigned basic::return_type_tinfo(void) const
+{
+    return tinfo();
+}
+
+unsigned basic::calchash(void) const
+{
+    unsigned v=golden_ratio_hash(tinfo());
+    for (int i=0; i<nops(); i++) {
+        v=rotate_left_31(v);
+        v ^= (const_cast<basic *>(this))->let_op(i).gethash();
+    }
+
+    v = v & 0x7FFFFFFFU;
+    
+    // store calculated hash value only if object is already evaluated
+    if (flags & status_flags::evaluated) {
+        setflag(status_flags::hash_calculated);
+        hashvalue=v;
+    }
+
+    return v;
+}
+
+ex basic::expand(unsigned options) const
+{
+    return this->setflag(status_flags::expanded);
+}
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+
+ex basic::subs(ex const & e) const
+{
+    // accept 2 types of replacement expressions:
+    //   - symbol==ex
+    //   - lst(symbol1==ex1,symbol2==ex2,...)
+    // convert to subs(lst(symbol1,symbol2,...),lst(ex1,ex2,...))
+    // additionally, idx can be used instead of symbol
+    if (e.info(info_flags::relation_equal)) {
+        return subs(lst(e));
+    }
+    if (!e.info(info_flags::list)) {
+        throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
+    }
+    lst ls;
+    lst lr;
+    for (int i=0; i<e.nops(); i++) {
+        if (!e.op(i).info(info_flags::relation_equal)) {
+            throw(std::invalid_argument("basic::subs(ex): argument must be a list or equations"));
+        }
+        if (!e.op(i).op(0).info(info_flags::symbol)) {
+            if (!e.op(i).op(0).info(info_flags::idx)) {
+                throw(std::invalid_argument("basic::subs(ex): lhs must be a symbol or an idx"));
+            }
+        }
+        ls.append(e.op(i).op(0));
+        lr.append(e.op(i).op(1));
+    }
+    return subs(ls,lr);
+}
+
+// compare functions to sort expressions canonically
+// all compare functions return: -1 for *this less than other, 0 equal, 1 greater
+
+/*
+int basic::compare(basic const & other) const
+{
+    const type_info & typeid_this = typeid(*this);
+    const type_info & typeid_other = typeid(other);
+
+    if (typeid_this==typeid_other) {
+        return compare_same_type(other);
+    }
+
+    // special rule: sort numeric() to end
+    if (typeid_this==typeid_numeric) return 1;
+    if (typeid_other==typeid_numeric) return -1;
+
+    // otherwise: sort according to type_info order (arbitrary, but well defined)
+    return typeid_this.before(typeid_other) ? -1 : 1;
+}
+*/
+
+int basic::compare(basic const & other) const
+{
+    unsigned hash_this = gethash();
+    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) {
+        /*
+        cout << "hash collision, different types: " 
+             << *this << " and " << other << endl;
+        this->printraw(cout);
+        cout << " and ";
+        other.printraw(cout);
+        cout << endl;
+        */
+        return -1;
+    }
+    if (typeid_this>typeid_other) {
+        /*
+        cout << "hash collision, different types: " 
+             << *this << " and " << other << endl;
+        this->printraw(cout);
+        cout << " and ";
+        other.printraw(cout);
+        cout << endl;
+        */
+        return 1;
+    }
+
+    ASSERT(typeid(*this)==typeid(other));
+
+    int cmpval=compare_same_type(other);
+    if ((cmpval!=0)&&(hash_this<0x80000000U)) {
+        /*
+        cout << "hash collision, same type: " 
+             << *this << " and " << other << endl;
+        this->printraw(cout);
+        cout << " and ";
+        other.printraw(cout);
+        cout << endl;
+        */
+    }
+    return cmpval;
+}
+
+bool basic::is_equal(basic const & other) const
+{
+    unsigned hash_this = gethash();
+    unsigned hash_other = other.gethash();
+
+    if (hash_this!=hash_other) return false;
+
+    unsigned typeid_this = tinfo();
+    unsigned typeid_other = other.tinfo();
+
+    if (typeid_this!=typeid_other) return false;
+
+    ASSERT(typeid(*this)==typeid(other));
+
+    return is_equal_same_type(other);
+}
+
+// protected
+
+basic const & basic::hold(void) const
+{
+    return setflag(status_flags::evaluated);
+}
+
+void basic::ensure_if_modifiable(void) const
+{
+    if (refcount>1) {
+        throw(std::runtime_error("cannot modify multiply referenced object"));
+    }
+}
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned basic::precedence=70;
+unsigned basic::delta_indent=4;
+
+//////////
+// global constants
+//////////
+
+const basic some_basic;
+type_info const & typeid_basic=typeid(some_basic);
+
+//////////
+// global variables
+//////////
+
+int max_recursion_level=1024;
diff --git a/ginac/basic.h b/ginac/basic.h
new file mode 100644 (file)
index 0000000..a095617
--- /dev/null
@@ -0,0 +1,240 @@
+/** @file basic.h
+ *
+ *  Interface to GiNaC's ABC. */
+
+#ifndef _BASIC_H_
+#define _BASIC_H_
+
+#include <iostream>
+#include <typeinfo>
+#include <vector>
+
+#include "flags.h"
+#include "tinfos.h"
+#include "debugmsg.h"
+
+class basic;
+class ex;
+class symbol;
+class lst;
+class numeric;
+
+typedef vector<ex> exvector;
+
+#define INLINE_BASIC_CONSTRUCTORS
+
+/** This class is the ABC (abstract base class) of GiNaC's class hierarchy.
+ *  It is responsible for the reference counting. */
+class basic
+{
+    friend class ex;
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    basic()
+#ifdef INLINE_BASIC_CONSTRUCTORS
+    : tinfo_key(TINFO_BASIC), flags(0), refcount(0)
+    {
+        debugmsg("basic default constructor",LOGLEVEL_CONSTRUCT);
+        // nothing to do
+    }
+#else
+;
+#endif // def INLINE_BASIC_CONSTRUCTORS
+
+    virtual ~basic()
+#ifdef INLINE_BASIC_CONSTRUCTORS
+    {
+        debugmsg("basic destructor",LOGLEVEL_DESTRUCT);
+        destroy(0);
+        ASSERT((!(flags & status_flags::dynallocated))||(refcount==0));
+    }
+#else
+;
+#endif // def INLINE_BASIC_CONSTRUCTORS
+
+    basic(basic const & other)
+#ifdef INLINE_BASIC_CONSTRUCTORS
+    {
+        debugmsg("basic copy constructor",LOGLEVEL_CONSTRUCT);
+        copy(other);
+    }
+#else
+;
+#endif // def INLINE_BASIC_CONSTRUCTORS
+
+    virtual basic const & operator=(basic const & other);
+    
+protected:
+    void copy(basic const & other)
+    {
+        flags = other.flags & ~status_flags::dynallocated;
+        hashvalue = other.hashvalue;
+        tinfo_key = other.tinfo_key;
+    }
+    void destroy(bool call_parent) {}
+
+    // other constructors
+    basic(unsigned ti)
+#ifdef INLINE_BASIC_CONSTRUCTORS
+    : tinfo_key(ti), flags(0), refcount(0)
+    {
+        debugmsg("basic constructor with tinfo_key",LOGLEVEL_CONSTRUCT);
+        // nothing to do
+    }
+#else
+;
+#endif // def INLINE_BASIC_CONSTRUCTORS
+
+    // functions overriding virtual functions from bases classes
+    // none
+    
+    // new virtual functions which can be overridden by derived classes
+public: // only const functions please (may break reference counting)
+    virtual basic * duplicate() const;
+    virtual void printraw(ostream & os) const;
+    virtual void printtree(ostream & os, unsigned indent) const;
+    virtual void print(ostream & os,unsigned upper_precedence=0) const;
+    virtual void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    virtual void dbgprint(void) const;
+    virtual void dbgprinttree(void) const;
+    virtual bool info(unsigned inf) const;
+    virtual int nops() const;
+    virtual ex op(int const i) const;
+    virtual ex & let_op(int const i);
+    virtual ex operator[](ex const & index) const;
+    virtual ex operator[](int const i) const;
+    virtual bool has(ex const & other) const;
+    virtual int degree(symbol const & s) const;
+    virtual int ldegree(symbol const & s) const;
+    virtual ex coeff(symbol const & s, int const n=1) const;
+    virtual ex collect(symbol const & s) const;
+    virtual ex eval(int level=0) const;
+    virtual ex evalf(int level=0) const;
+    virtual ex diff(symbol const & s) const;
+    virtual ex series(symbol const & s, ex const & point, int order) const;
+    virtual ex subs(lst const & ls, lst const & lr) const;
+    virtual ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+    virtual numeric integer_content(void) const;
+    virtual ex smod(numeric const &xi) const;
+    virtual numeric max_coefficient(void) const;
+    virtual exvector get_indices(void) const;
+    virtual ex simplify_ncmul(exvector const & v) const;
+protected: // non-const functions should be called from class ex only
+    virtual int compare_same_type(basic const & other) const;
+    virtual bool is_equal_same_type(basic const & other) const;
+    virtual unsigned return_type(void) const;
+    virtual unsigned return_type_tinfo(void) const;
+    virtual unsigned calchash(void) const;
+    virtual ex expand(unsigned options=0) const;
+
+    // non-virtual functions in this class
+public:
+    ex subs(ex const & e) const;
+    int compare(basic const & other) const;
+    bool is_equal(basic const & other) const;
+    basic const & 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;}
+protected:
+    basic const & setflag(unsigned f) const {flags |= f; return *this;}
+    basic const & clearflag(unsigned f) const {flags &= ~f; return *this;}
+    void ensure_if_modifiable(void) const;
+
+// member variables
+    
+protected:
+    unsigned tinfo_key;
+    mutable unsigned flags;
+    mutable unsigned hashvalue;
+    static unsigned precedence;
+    static unsigned delta_indent;
+private:
+    unsigned refcount;
+};
+
+// global constants
+
+extern const basic some_basic;
+extern type_info const & typeid_basic;
+
+// global variables
+
+extern int max_recursion_level;
+
+/*
+#ifndef _DEBUG
+*/
+#define is_of_type(OBJ,TYPE) \
+    (dynamic_cast<TYPE *>(const_cast<basic *>(&OBJ))!=0)
+
+/*
+#define is_exactly_of_type(OBJ,TYPE) \
+    (typeid(OBJ)==typeid(some_##TYPE))
+*/
+#define is_exactly_of_type(OBJ,TYPE) \
+    ((OBJ).tinfo()==(some_##TYPE).tinfo())
+
+
+    /*
+#else 
+#define is_of_type(OBJ,TYPE)                               \
+    (ASSERT(typeid(OBJ)!=typeid(exZERO())),                \
+     (dynamic_cast<TYPE *>(const_cast<basic *>(&OBJ))!=0))
+
+#define is_exactly_of_type(OBJ,TYPE)                       \
+    (ASSERT(typeid(OBJ)!=typeid(exZERO())),                \
+     (typeid(OBJ)==typeid(some_##TYPE))
+#endif // ndef _DEBUG
+*/
+
+#define is_ex_of_type(OBJ,TYPE) \
+    (dynamic_cast<TYPE *>(const_cast<basic *>((OBJ).bp))!=0)
+
+/*
+#define is_ex_exactly_of_type(OBJ,TYPE) \
+    (typeid(*(OBJ).bp)==typeid(some_##TYPE))
+*/
+
+#define is_ex_exactly_of_type(OBJ,TYPE) \
+    ((*(OBJ).bp).tinfo()==(some_##TYPE).tinfo())
+
+#define are_ex_trivially_equal(EX1,EX2) \
+    ((EX1).bp==(EX2).bp)
+
+// global functions
+
+inline unsigned rotate_left_31(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;
+    }
+
+    ASSERT(n<0x80000000U);
+
+    return n;
+}
+
+inline unsigned golden_ratio_hash(unsigned n)
+{
+#if 0
+       // This requires Â´long long´ (or an equivalent 64 bit type)---which is,
+    // unfortunately, not ANSI-compliant:
+       unsigned long long l = n * 0x4f1bbcddLL;
+       return (l & 0x7fffffffU) ^ (l >> 32);
+#else
+       // This requires Â´long double´ to have a mantissa of at least 64 bit---
+    // which is not guaranteed by any standard:
+    const static long double golden_ratio=.618033988749894848204586834370;
+    long double m=golden_ratio*n;
+    return unsigned((m-int(m))*0x80000000);
+#endif
+}
+
+#endif // ndef _BASIC_H_
diff --git a/ginac/clifford.cpp b/ginac/clifford.cpp
new file mode 100644 (file)
index 0000000..98f3652
--- /dev/null
@@ -0,0 +1,190 @@
+/** @file clifford.cpp
+ *
+ *  Implementation of GiNaC's clifford objects.
+ *  No real implementation yet, to be done.     */
+
+#include <string>
+
+#include "ginac.h"
+#include "utils.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+clifford::clifford()
+{
+    debugmsg("clifford default constructor",LOGLEVEL_CONSTRUCT);
+    serial=next_serial++;
+    name=autoname_prefix()+ToString(serial);
+    tinfo_key=TINFO_CLIFFORD;
+}
+
+clifford::~clifford()
+{
+    debugmsg("clifford destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+clifford::clifford(clifford const & other)
+{
+    debugmsg("clifford copy constructor",LOGLEVEL_CONSTRUCT);
+    copy (other);
+}
+
+clifford const & clifford::operator=(clifford const & other)
+{
+    debugmsg("clifford operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void clifford::copy(clifford const & other)
+{
+    indexed::copy(other);
+    name=other.name;
+    serial=other.serial;
+}
+
+void clifford::destroy(bool call_parent)
+{
+    if (call_parent) {
+        indexed::destroy(call_parent);
+    }
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+clifford::clifford(string const & initname)
+{
+    debugmsg("clifford constructor from string",LOGLEVEL_CONSTRUCT);
+    name=initname;
+    serial=next_serial++;
+    tinfo_key=TINFO_CLIFFORD;
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * clifford::duplicate() const
+{
+    debugmsg("clifford duplicate",LOGLEVEL_DUPLICATE);
+    return new clifford(*this);
+}
+
+void clifford::printraw(ostream & os) const
+{
+    debugmsg("clifford printraw",LOGLEVEL_PRINT);
+    os << "clifford(" << "name=" << name << ",serial=" << serial
+       << ",indices=";
+    printrawindices(os);
+    os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+}
+
+void clifford::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("clifford printtree",LOGLEVEL_PRINT);
+    os << string(indent,' ') << name << " (clifford): "
+       << "serial=" << serial << ","
+       << seq.size() << "indices=";
+    printtreeindices(os,indent);
+    os << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void clifford::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("clifford print",LOGLEVEL_PRINT);
+    os << name;
+    printindices(os);
+}
+
+void clifford::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("clifford print csrc",LOGLEVEL_PRINT);
+    print(os,upper_precedence);
+}
+
+bool clifford::info(unsigned inf) const
+{
+    return indexed::info(inf);
+}
+
+// protected
+
+int clifford::compare_same_type(basic const & other) const
+{
+    ASSERT(other.tinfo() == TINFO_CLIFFORD);
+    const clifford *o = static_cast<const clifford *>(&other);
+    if (serial==o->serial) {
+        return indexed::compare_same_type(other);
+    }
+    return serial < o->serial ? -1 : 1;
+}
+
+ex clifford::simplify_ncmul(exvector const & v) const
+{
+    return simplified_ncmul(v);
+}
+
+unsigned clifford::calchash(void) const
+{
+    hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555556U ^
+                                                  golden_ratio_hash(tinfo_key) ^
+                                                  serial));
+    setflag(status_flags::hash_calculated);
+    return hashvalue;
+}
+
+//////////
+// virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+void clifford::setname(string const & n)
+{
+    name=n;
+}
+
+// private
+
+string & clifford::autoname_prefix(void)
+{
+    static string * s=new string("clifford");
+    return *s;
+}
+
+//////////
+// static member variables
+//////////
+
+// private
+
+unsigned clifford::next_serial=0;
+
+//////////
+// global constants
+//////////
+
+const clifford some_clifford;
+type_info const & typeid_clifford=typeid(some_clifford);
+
diff --git a/ginac/clifford.h b/ginac/clifford.h
new file mode 100644 (file)
index 0000000..65ec005
--- /dev/null
@@ -0,0 +1,75 @@
+/** @file clifford.h
+ *
+ *  Interface to GiNaC's clifford objects. */
+
+#ifndef _CLIFFORD_H_
+#define _CLIFFORD_H_
+
+#include <string>
+
+class clifford;
+
+#include "indexed.h"
+
+/** Base class for clifford object */
+class clifford : public indexed
+{
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    clifford();
+    ~clifford();
+    clifford(clifford const & other);
+    clifford const & operator=(clifford const & other);
+protected:
+    void copy(clifford const & other); 
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    explicit clifford(string const & initname);
+
+    // functions overriding virtual functions from base classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    ex simplify_ncmul(exvector const & v) const;
+    unsigned calchash(void) const;
+
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+public:
+    void setname(string const & n);
+private:
+    string & autoname_prefix(void);
+
+// member variables
+
+protected:
+    string name;
+    unsigned serial; // unique serial number for comparision
+private:
+    static unsigned next_serial;
+};
+
+// global constants
+
+extern const clifford some_clifford;
+extern type_info const & typeid_clifford;
+
+// macros
+
+#define ex_to_clifford(X) static_cast<clifford const &>(*(X).bp)
+
+#endif // ndef _CLIFFORD_H_
+
+
diff --git a/ginac/color.cpp b/ginac/color.cpp
new file mode 100644 (file)
index 0000000..f790e94
--- /dev/null
@@ -0,0 +1,953 @@
+/** @file color.cpp
+ *
+ *  Implementation of GiNaC's color objects.
+ *  No real implementation yet, to be done.     */
+
+#include <string>
+#include <list>
+#include <algorithm>
+#include <iostream>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+color::color() : type(invalid), representation_label(0)
+{
+    debugmsg("color default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_COLOR;
+}
+
+color::~color()
+{
+    debugmsg("color destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+color::color(color const & other)
+{
+    debugmsg("color copy constructor",LOGLEVEL_CONSTRUCT);
+    copy (other);
+}
+
+color const & color::operator=(color const & other)
+{
+    debugmsg("color operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+       copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void color::copy(color const & other)
+{
+    indexed::copy(other);
+    type=other.type;
+    representation_label=other.representation_label;
+}
+
+void color::destroy(bool call_parent)
+{
+    if (call_parent) {
+        indexed::destroy(call_parent);
+    }
+}
+
+//////////
+// other constructors
+//////////
+
+// protected
+
+color::color(color_types const t, unsigned const rl) : type(t), representation_label(rl)
+{
+    debugmsg("color constructor from color_types,unsigned",LOGLEVEL_CONSTRUCT);
+    ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+    tinfo_key=TINFO_COLOR;
+    ASSERT(all_of_type_coloridx());
+}
+
+color::color(color_types const t, ex const & i1, unsigned const rl)
+    : indexed(i1), type(t), representation_label(rl)
+{
+    debugmsg("color constructor from color_types,ex,unsigned",LOGLEVEL_CONSTRUCT);
+    ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+    tinfo_key=TINFO_COLOR;
+    ASSERT(all_of_type_coloridx());
+}
+
+color::color(color_types const t, ex const & i1, ex const & i2, unsigned const rl)
+    : indexed(i1,i2), type(t), representation_label(rl)
+{
+    debugmsg("color constructor from color_types,ex,ex,unsigned",LOGLEVEL_CONSTRUCT);
+    ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+    tinfo_key=TINFO_COLOR;
+    ASSERT(all_of_type_coloridx());
+}
+
+color::color(color_types const t, ex const & i1, ex const & i2, ex const & i3,
+             unsigned const rl) : indexed(i1,i2,i3), type(t), representation_label(rl)
+{
+    debugmsg("color constructor from color_types,ex,ex,ex,unsigned",LOGLEVEL_CONSTRUCT);
+    ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+    tinfo_key=TINFO_COLOR;
+    ASSERT(all_of_type_coloridx());
+}
+
+color::color(color_types const t, exvector const & iv, unsigned const rl)
+    : indexed(iv), type(t), representation_label(rl)
+{
+    debugmsg("color constructor from color_types,exvector,unsigned",LOGLEVEL_CONSTRUCT);
+    ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+    tinfo_key=TINFO_COLOR;
+    ASSERT(all_of_type_coloridx());
+}
+
+color::color(color_types const t, exvector * ivp, unsigned const rl)
+    : indexed(ivp), type(t), representation_label(rl)
+{
+    debugmsg("color constructor from color_types,exvector *,unsigned",LOGLEVEL_CONSTRUCT);
+    ASSERT(representation_label<MAX_REPRESENTATION_LABELS);
+    tinfo_key=TINFO_COLOR;
+    ASSERT(all_of_type_coloridx());
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * color::duplicate() const
+{
+    debugmsg("color duplicate",LOGLEVEL_DUPLICATE);
+    return new color(*this);
+}
+
+void color::printraw(ostream & os) const
+{
+    debugmsg("color printraw",LOGLEVEL_PRINT);
+    os << "color(type=" << (unsigned)type
+       << ",representation_label=" << representation_label
+       << ",indices=";
+    printrawindices(os);
+    os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+}
+
+void color::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("color printtree",LOGLEVEL_PRINT);
+    os << string(indent,' ') << "color object: "
+       << "type=" << (unsigned)type
+       << ",representation_label=" << representation_label << ", ";
+    os << seq.size() << " indices" << endl;
+    printtreeindices(os,indent);
+    os << string(indent,' ') << "hash=" << hashvalue
+       << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void color::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("color print",LOGLEVEL_PRINT);
+    switch (type) {
+    case color_T:
+        os << "T";
+        if (representation_label!=0) {
+            os << "^(" << representation_label << ")";
+        }
+        break;
+    case color_f:
+        os << "f";
+        break;
+    case color_d:
+        os << "d";
+        break;
+    case color_delta8:
+        os << "delta8";
+        break;
+    case color_ONE:
+        os << "color_ONE";
+        break;
+    case invalid:
+    default:
+        os << "INVALID_COLOR_OBJECT";
+        break;
+    }
+    printindices(os);
+}
+
+void color::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("color print csrc",LOGLEVEL_PRINT);
+    print(os,upper_precedence);
+}
+
+bool color::info(unsigned inf) const
+{
+    return indexed::info(inf);
+}
+
+#define CMPINDICES(A,B,C) ((idx1.get_value()==(A))&&(idx2.get_value()==(B))&&(idx3.get_value()==(C)))
+
+ex color::eval(int level) const
+{
+    // canonicalize indices
+    
+    bool antisymmetric=false;
+    
+    switch (type) {
+    case color_f:
+        antisymmetric=true; // no break here!
+    case color_d:
+    case color_delta8:
+        {
+            exvector iv=seq;
+            int sig=canonicalize_indices(iv,antisymmetric);
+            if (sig!=INT_MAX) {
+                // something has changed while sorting indices, more evaluations later
+                if (sig==0) return exZERO();
+                return ex(sig)*color(type,iv,representation_label);
+            }
+        }
+        break;
+    default:
+        // nothing to canonicalize
+        break;
+    }
+
+    switch (type) {
+    case color_delta8:
+        {
+            ASSERT(seq.size()==2);
+            coloridx const & idx1=ex_to_coloridx(seq[0]);
+            coloridx const & idx2=ex_to_coloridx(seq[1]);
+            
+            // check for delta8_{a,a} where a is a symbolic index, replace by 8
+            if ((idx1.is_symbolic())&&(idx1.is_equal_same_type(idx2))) {
+                return ex(COLOR_EIGHT);
+            }
+
+            // check for delta8_{a,b} where a and b are numeric indices, replace by 0 or 1
+            if ((!idx1.is_symbolic())&&(!idx2.is_symbolic())) {
+                if ((idx1.get_value()!=idx2.get_value())) {
+                    return exONE();
+                } else {
+                    return exZERO();
+                }
+            }
+       }
+        break;
+    case color_d:
+        // check for d_{a,a,c} (=0) when a is symbolic
+        {
+            ASSERT(seq.size()==3);
+            coloridx const & idx1=ex_to_coloridx(seq[0]);
+            coloridx const & idx2=ex_to_coloridx(seq[1]);
+            coloridx const & idx3=ex_to_coloridx(seq[2]);
+            
+            if (idx1.is_equal_same_type(idx2) && idx1.is_symbolic()) {
+                return exZERO();
+            } else if (idx2.is_equal_same_type(idx3) && idx2.is_symbolic()) {
+                return exZERO();
+            }
+            
+            // check for three numeric indices
+            if (!(idx1.is_symbolic()||idx2.is_symbolic()||idx3.is_symbolic())) {
+                ASSERT(idx1.get_value()<=idx2.get_value());
+                ASSERT(idx2.get_value()<=idx3.get_value());
+                if (CMPINDICES(1,4,6)||CMPINDICES(1,5,7)||CMPINDICES(2,5,6)||
+                    CMPINDICES(3,4,4)||CMPINDICES(3,5,5)) {
+                    return exHALF();
+                } else if (CMPINDICES(2,4,7)||CMPINDICES(3,6,6)||CMPINDICES(3,7,7)) {
+                    return -exHALF();
+                } else if (CMPINDICES(1,1,8)||CMPINDICES(2,2,8)||CMPINDICES(3,3,8)) {
+                    return 1/sqrt(numeric(3));
+                } else if (CMPINDICES(8,8,8)) {
+                    return -1/sqrt(numeric(3));
+                } else if (CMPINDICES(4,4,8)||CMPINDICES(5,5,8)||CMPINDICES(6,6,8)||CMPINDICES(7,7,8)) {
+                    return -1/(2*sqrt(numeric(3)));
+                }
+                return exZERO();
+            }
+        }
+        break;
+    case color_f:
+        {
+            ASSERT(seq.size()==3);
+            coloridx const & idx1=ex_to_coloridx(seq[0]);
+            coloridx const & idx2=ex_to_coloridx(seq[1]);
+            coloridx const & idx3=ex_to_coloridx(seq[2]);
+            
+            // check for three numeric indices
+            if (!(idx1.is_symbolic()||idx2.is_symbolic()||idx3.is_symbolic())) {
+                ASSERT(idx1.get_value()<=idx2.get_value());
+                ASSERT(idx2.get_value()<=idx3.get_value());
+                if (CMPINDICES(1,2,3)) {
+                    return exONE();
+                } else if (CMPINDICES(1,4,7)||CMPINDICES(2,4,6)||
+                           CMPINDICES(2,5,7)||CMPINDICES(3,4,5)) {
+                    return exHALF();
+                } else if (CMPINDICES(1,5,6)||CMPINDICES(3,6,7)) {
+                    return -exHALF();
+                } else if (CMPINDICES(4,5,8)||CMPINDICES(6,7,8)) {
+                    return sqrt(numeric(3))/2;
+                } else if (CMPINDICES(8,8,8)) {
+                    return -1/sqrt(numeric(3));
+                } else if (CMPINDICES(4,4,8)||CMPINDICES(5,5,8)||CMPINDICES(6,6,8)||CMPINDICES(7,7,8)) {
+                    return -1/(2*sqrt(numeric(3)));
+                }
+                return exZERO();
+            }
+            break;
+        }
+    default:
+        // nothing to evaluate
+        break;
+    }
+    
+    return this->hold();
+}
+    
+// protected
+
+int color::compare_same_type(basic const & other) const
+{
+    ASSERT(other.tinfo() == TINFO_COLOR);
+    const color *o = static_cast<const color *>(&other);
+    if (type==o->type) {
+        if (representation_label==o->representation_label) {
+            return indexed::compare_same_type(other);
+        }
+        return representation_label < o->representation_label ? -1 : 1;
+    }
+    return type < o->type ? -1 : 1;
+}
+
+bool color::is_equal_same_type(basic const & other) const
+{
+    ASSERT(other.tinfo() == TINFO_COLOR);
+    const color *o = static_cast<const color *>(&other);
+    if (type!=o->type) return false;
+    if (representation_label!=o->representation_label) return false;
+    return indexed::is_equal_same_type(other);
+}
+
+#include <iostream>
+
+ex color::simplify_ncmul(exvector const & v) const
+{
+    // simplifications: contract delta8_{a,b} where possible
+    //                  sort delta8,f,d,T(rl=0),T(rl=1),...,ONE(rl=0),ONE(rl=1),...
+    //                  remove superfluous ONEs
+    
+    // contract indices of delta8_{a,b} if they are different and symbolic
+
+    exvector v_contracted=v;
+    unsigned replacements;
+    bool something_changed=false;
+
+    exvector::iterator it=v_contracted.begin();
+    while (it!=v_contracted.end()) {
+        // process only delta8 objects
+        if (is_ex_exactly_of_type(*it,color) && (ex_to_color(*it).type==color_delta8)) {
+            color & d8=ex_to_nonconst_color(*it);
+            ASSERT(d8.seq.size()==2);
+            coloridx const & first_idx=ex_to_coloridx(d8.seq[0]);
+            coloridx const & second_idx=ex_to_coloridx(d8.seq[1]);
+            // delta8_{a,a} should have been contracted in color::eval()
+            ASSERT((!first_idx.is_equal(second_idx))||(!first_idx.is_symbolic()));
+            ex saved_delta8=*it; // save to restore it later
+
+            // try to contract first index
+            replacements=1;
+            if (first_idx.is_symbolic()) {
+                replacements = subs_index_in_exvector(v_contracted,first_idx,second_idx);
+                if (replacements==1) {
+                    // not contracted except in itself, restore delta8 object
+                    *it=saved_delta8;
+                } else {
+                    // a contracted index should occur exactly twice
+                    ASSERT(replacements==2);
+                    *it=exONE();
+                    something_changed=true;
+                }
+            }
+
+            // try second index only if first was not contracted
+            if ((replacements==1)&&(second_idx.is_symbolic())) {
+                // first index not contracted, *it is guaranteed to be the original delta8 object
+                replacements = subs_index_in_exvector(v_contracted,second_idx,first_idx);
+                if (replacements==1) {
+                    // not contracted except in itself, restore delta8 object
+                    *it=saved_delta8;
+                } else {
+                    // a contracted index should occur exactly twice
+                    ASSERT(replacements==2);
+                    *it=exONE();
+                    something_changed=true;
+                }
+            }
+        }
+        ++it;
+    }
+
+    if (something_changed) {
+        // do more simplifications later
+        return nonsimplified_ncmul(v_contracted);
+    }
+
+    // there were no indices to contract
+    // sort delta8,f,d,T(rl=0),T(rl=1),...,ONE(rl=0),ONE(rl=1),...,unknown
+    // (if there is at least one unknown object, all Ts will be unknown to not change the order)
+    
+    exvector delta8vec;
+    exvector fvec;
+    exvector dvec;
+    vector<exvector> Tvecs;
+    Tvecs.resize(MAX_REPRESENTATION_LABELS);
+    vector<exvector> ONEvecs;
+    ONEvecs.resize(MAX_REPRESENTATION_LABELS);
+    exvector unknownvec;
+    
+    split_color_string_in_parts(v,delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
+
+    // d_{a,k,l} f_{b,k,l}=0 (includes case a=b)
+    if ((dvec.size()>=1)&&(fvec.size()>=1)) {
+        for (exvector::iterator it1=dvec.begin(); it1!=dvec.end(); ++it1) {
+            for (exvector::iterator it2=fvec.begin(); it2!=fvec.end(); ++it2) {
+                ASSERT(is_ex_exactly_of_type(*it1,color));
+                ASSERT(is_ex_exactly_of_type(*it2,color));
+                color const & col1=ex_to_color(*it1);
+                color const & col2=ex_to_color(*it2);
+                exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
+                if (iv_intersect.size()>=2) return exZERO();
+            }
+        }
+    }
+    
+    // d_{a,k,l} d_{b,k,l}=5/3 delta8_{a,b} (includes case a=b)
+    if (dvec.size()>=2) {
+        for (exvector::iterator it1=dvec.begin(); it1!=dvec.end()-1; ++it1) {
+            for (exvector::iterator it2=it1+1; it2!=dvec.end(); ++it2) {
+                ASSERT(is_ex_exactly_of_type(*it1,color));
+                ASSERT(is_ex_exactly_of_type(*it2,color));
+                color const & col1=ex_to_color(*it1);
+                color const & col2=ex_to_color(*it2);
+                exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
+                if (iv_intersect.size()>=2) {
+                    if (iv_intersect.size()==3) {
+                        *it1=numeric(40)/numeric(3);
+                        *it2=exONE();
+                    } else {
+                        int sig1, sig2; // unimportant, since symmetric
+                        ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,false,&sig1);
+                        ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,false,&sig2);
+                        *it1=numeric(5)/numeric(3)*color(color_delta8,idx1,idx2);
+                        *it2=exONE();
+                    }
+                    return nonsimplified_ncmul(recombine_color_string(
+                           delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+                }
+            }
+        }
+    }
+
+    // f_{a,k,l} f_{b,k,l}=3 delta8_{a,b} (includes case a=b)
+    if (fvec.size()>=2) {
+        for (exvector::iterator it1=fvec.begin(); it1!=fvec.end()-1; ++it1) {
+            for (exvector::iterator it2=it1+1; it2!=fvec.end(); ++it2) {
+                ASSERT(is_ex_exactly_of_type(*it1,color));
+                ASSERT(is_ex_exactly_of_type(*it2,color));
+                color const & col1=ex_to_color(*it1);
+                color const & col2=ex_to_color(*it2);
+                exvector iv_intersect=idx_intersect(col1.seq,col2.seq);
+                if (iv_intersect.size()>=2) {
+                    if (iv_intersect.size()==3) {
+                        *it1=numeric(24);
+                        *it2=exONE();
+                    } else {
+                        int sig1, sig2;
+                        ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,true,&sig1);
+                        ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,true,&sig2);
+                        *it1=numeric(sig1*sig2*5)/numeric(3)*color(color_delta8,idx1,idx2);
+                        *it2=exONE();
+                    }
+                    return nonsimplified_ncmul(recombine_color_string(
+                           delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+                }
+            }
+        }
+    }
+
+    // d_{a,b,c} T_b T_c = 5/6 T_a
+    // f_{a,b,c} T_b T_c = 3/2 I T_a
+    for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+        if ((Tvecs[rl].size()>=2)&&((dvec.size()>=1)||(fvec.size()>=1))) {
+            for (exvector::iterator it1=Tvecs[rl].begin(); it1!=Tvecs[rl].end()-1; ++it1) {
+                exvector iv;
+                ASSERT(is_ex_exactly_of_type(*it1,color)&&ex_to_color(*it1).type==color_T);
+                ASSERT(is_ex_exactly_of_type(*(it1+1),color)&&ex_to_color(*(it1+1)).type==color_T);
+                iv.push_back(ex_to_color(*it1).seq[0]);
+                iv.push_back(ex_to_color(*(it1+1)).seq[0]);
+                
+                // d_{a,b,c} T_b T_c = 5/6 T_a
+                for (exvector::iterator it2=dvec.begin(); it2!=dvec.end(); ++it2) {
+                    ASSERT(is_ex_exactly_of_type(*it2,color)&&ex_to_color(*it2).type==color_d);
+                    color const & dref=ex_to_color(*it2);
+                    exvector iv_intersect=idx_intersect(dref.seq,iv);
+                    if (iv_intersect.size()==2) {
+                        int sig; // unimportant, since symmetric
+                        ex free_idx=permute_free_index_to_front(dref.seq,iv,false,&sig);
+                        *it1=color(color_T,free_idx,rl);
+                        *(it1+1)=color(color_ONE,rl);
+                        *it2=numeric(5)/numeric(6);
+                        return nonsimplified_ncmul(recombine_color_string(
+                               delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+                    }
+                }
+
+                // f_{a,b,c} T_b T_c = 3/2 I T_a
+                for (exvector::iterator it2=fvec.begin(); it2!=fvec.end(); ++it2) {
+                    ASSERT(is_ex_exactly_of_type(*it2,color)&&ex_to_color(*it2).type==color_f);
+                    color const & fref=ex_to_color(*it2);
+                    exvector iv_intersect=idx_intersect(fref.seq,iv);
+                    if (iv_intersect.size()==2) {
+                        int sig;
+                        ex free_idx=permute_free_index_to_front(fref.seq,iv,true,&sig);
+                        *it1=color(color_T,free_idx,rl);
+                        *(it1+1)=color(color_ONE,rl);
+                        *it2=numeric(sig*3)/numeric(2)*I;
+                        return nonsimplified_ncmul(recombine_color_string(
+                               delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+                    }
+                }
+            }
+        }
+    }
+    
+    // clear all ONEs when there is at least one corresponding color_T
+    // in this representation, retain one ONE otherwise
+    for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+        if (Tvecs[rl].size()!=0) {
+            ONEvecs[rl].clear();
+        } else if (ONEvecs[rl].size()!=0) {
+            ONEvecs[rl].clear();
+            ONEvecs[rl].push_back(color(color_ONE,rl));
+        }
+    }
+
+    // return a sorted vector
+    return simplified_ncmul(recombine_color_string(delta8vec,fvec,dvec,Tvecs,
+                                                   ONEvecs,unknownvec));
+}
+
+ex color::thisexprseq(exvector const & v) const
+{
+    return color(type,v,representation_label);
+}
+
+ex color::thisexprseq(exvector * vp) const
+{
+    return color(type,vp,representation_label);
+}
+
+bool color::all_of_type_coloridx(void) const
+{
+    // used only inside of ASSERTs
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        if (!is_ex_of_type(*cit,coloridx)) return false;
+    }
+    return true;
+}
+
+//////////
+// virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const color some_color;
+type_info const & typeid_color=typeid(some_color);
+
+//////////
+// friend functions
+//////////
+
+color color_ONE(unsigned const rl)
+{
+    return color(color::color_ONE,rl);
+}
+
+color color_T(ex const & a, unsigned const rl)
+{
+    return color(color::color_T,a,rl);
+}
+
+color color_f(ex const & a, ex const & b, ex const & c)
+{
+    return color(color::color_f,a,b,c);
+}
+
+color color_d(ex const & a, ex const & b, ex const & c)
+{
+    return color(color::color_d,a,b,c);
+}
+
+ex color_h(ex const & a, ex const & b, ex const & c)
+{
+    return color(color::color_d,a,b,c)+I*color(color::color_f,a,b,c);
+}
+
+color color_delta8(ex const & a, ex const & b)
+{
+    return color(color::color_delta8,a,b);
+}
+
+void split_color_string_in_parts(exvector const & v, exvector & delta8vec,
+                                 exvector & fvec, exvector & dvec,
+                                 vector<exvector> & Tvecs,
+                                 vector<exvector> & ONEvecs,
+                                 exvector & unknownvec)
+{
+    // if not all elements are of type color, put all Ts in unknownvec to
+    // retain the ordering
+    bool all_color=true;
+    for (exvector::const_iterator cit=v.begin(); cit!=v.end(); ++cit) {
+        if (!is_ex_exactly_of_type(*cit,color)) {
+            all_color=false;
+            break;
+        }
+    }
+    
+    for (exvector::const_iterator cit=v.begin(); cit!=v.end(); ++cit) {
+        if (is_ex_exactly_of_type(*cit,color)) {
+            switch (ex_to_color(*cit).type) {
+            case color::color_delta8:
+                delta8vec.push_back(*cit);
+                break;
+            case color::color_f:
+                fvec.push_back(*cit);
+                break;
+            case color::color_d:
+                dvec.push_back(*cit);
+                break;
+            case color::color_T:
+                ASSERT(ex_to_color(*cit).representation_label<MAX_REPRESENTATION_LABELS);
+                if (all_color) {
+                    Tvecs[ex_to_color(*cit).representation_label].push_back(*cit);
+                } else {
+                    unknownvec.push_back(*cit);
+                }
+                break;
+            case color::color_ONE:
+                ASSERT(ex_to_color(*cit).representation_label<MAX_REPRESENTATION_LABELS);
+                ONEvecs[ex_to_color(*cit).representation_label].push_back(*cit);
+                break;
+            default:
+                throw(std::logic_error("invalid type in split_color_string_in_parts()"));
+            }
+        } else {
+            unknownvec.push_back(*cit);
+        }
+    }
+}    
+
+exvector recombine_color_string(exvector & delta8vec, exvector & fvec,
+                                exvector & dvec, vector<exvector> & Tvecs,
+                                vector<exvector> & ONEvecs, exvector & unknownvec)
+{
+    unsigned sz=delta8vec.size()+fvec.size()+dvec.size()+unknownvec.size();
+    for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+        sz += Tvecs[rl].size();
+        sz += ONEvecs[rl].size();
+    }
+    exvector v;
+    v.reserve(sz);
+    
+    append_exvector_to_exvector(v,delta8vec);
+    append_exvector_to_exvector(v,fvec);
+    append_exvector_to_exvector(v,dvec);
+    for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+        append_exvector_to_exvector(v,Tvecs[rl]);
+        append_exvector_to_exvector(v,ONEvecs[rl]);
+    }
+    append_exvector_to_exvector(v,unknownvec);
+    return v;
+}
+
+ex color_trace_of_one_representation_label(exvector const & v)
+{
+    if (v.size()==0) {
+        return numeric(COLOR_THREE);
+    } else if (v.size()==1) {
+        ASSERT(is_ex_exactly_of_type(*(v.begin()),color));
+        return exZERO();
+    }
+    exvector v1=v;
+    ex last_element=v1.back();
+    ASSERT(is_ex_exactly_of_type(last_element,color));
+    ASSERT(ex_to_color(last_element).type==color::color_T);
+    v1.pop_back();
+    ex next_to_last_element=v1.back();
+    ASSERT(is_ex_exactly_of_type(next_to_last_element,color));
+    ASSERT(ex_to_color(next_to_last_element).type==color::color_T);
+    v1.pop_back();
+    exvector v2=v1;
+
+    ex const & last_index=ex_to_color(last_element).seq[0];
+    ex const & next_to_last_index=ex_to_color(next_to_last_element).seq[0];
+    ex summation_index=coloridx();
+
+    v2.push_back(color_T(summation_index)); // don't care about the representation_label
+    
+    // check this formula for SU(N) with N!=3 !!!!!!!!!
+    return numeric(1)/numeric(2*COLOR_THREE)*color_delta8(next_to_last_index,last_index)
+           % color_trace_of_one_representation_label(v1)
+          +numeric(1)/numeric(2)*color_h(next_to_last_index,last_index,summation_index)
+           % color_trace_of_one_representation_label(v2);
+    /*
+    ex term1=numeric(1)/numeric(2*COLOR_THREE)*color_delta8(next_to_last_index,last_index)
+           % color_trace_of_one_representation_label(v1);
+    cout << "term 1 of trace of " << v.size() << " ts=" << term1 << endl;
+    ex term2=numeric(1)/numeric(2)*color_h(next_to_last_index,last_index,summation_index)
+           % color_trace_of_one_representation_label(v2);
+    cout << "term 2 of trace of " << v.size() << " ts=" << term2 << endl;
+    return term1+term2;
+    */
+}
+
+ex color_trace(exvector const & v, unsigned const rl)
+{
+    ASSERT(rl<MAX_REPRESENTATION_LABELS);
+    
+    exvector v_rest;
+    v_rest.reserve(v.size()+1); // max size if trace is empty
+    
+    exvector delta8vec;
+    exvector fvec;
+    exvector dvec;
+    vector<exvector> Tvecs;
+    Tvecs.resize(MAX_REPRESENTATION_LABELS);
+    vector<exvector> ONEvecs;
+    ONEvecs.resize(MAX_REPRESENTATION_LABELS);
+    exvector unknownvec;
+
+    split_color_string_in_parts(v,delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
+
+    if (unknownvec.size()!=0) {
+        throw(std::invalid_argument("color_trace(): expression must be expanded"));
+    }
+
+    append_exvector_to_exvector(v_rest,delta8vec);
+    append_exvector_to_exvector(v_rest,fvec);
+    append_exvector_to_exvector(v_rest,dvec);
+    for (unsigned i=0; i<MAX_REPRESENTATION_LABELS; ++i) {
+        if (i!=rl) {
+            append_exvector_to_exvector(v_rest,Tvecs[i]);
+            append_exvector_to_exvector(v_rest,ONEvecs[i]);
+        } else {
+            if (Tvecs[i].size()!=0) {
+                v_rest.push_back(color_trace_of_one_representation_label(Tvecs[i]));
+            } else if (ONEvecs[i].size()!=0) {
+                v_rest.push_back(numeric(COLOR_THREE));
+            } else {
+                throw(std::logic_error("color_trace(): representation_label not in color string"));
+            }
+        }
+    }
+
+    return nonsimplified_ncmul(v_rest);
+}
+
+ex simplify_pure_color_string(ex const & e)
+{
+    ASSERT(is_ex_exactly_of_type(e,ncmul));
+
+    exvector delta8vec;
+    exvector fvec;
+    exvector dvec;
+    vector<exvector> Tvecs;
+    Tvecs.resize(MAX_REPRESENTATION_LABELS);
+    vector<exvector> ONEvecs;
+    ONEvecs.resize(MAX_REPRESENTATION_LABELS);
+    exvector unknownvec;
+
+    split_color_string_in_parts(ex_to_ncmul(e).get_factors(),delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec);
+
+    // search for T_k S T_k (=1/2 Tr(S) - 1/6 S)
+    for (unsigned rl=0; rl<MAX_REPRESENTATION_LABELS; ++rl) {
+        if (Tvecs[rl].size()>=2) {
+            for (unsigned i=0; i<Tvecs[rl].size()-1; ++i) {
+                for (unsigned j=i+1; j<Tvecs[rl].size(); ++j) {
+                    ex & t1=Tvecs[rl][i];
+                    ex & t2=Tvecs[rl][j];
+                    ASSERT(is_ex_exactly_of_type(t1,color)&&
+                           (ex_to_color(t1).type==color::color_T)&&
+                           (ex_to_color(t1).seq.size()==1));
+                    ASSERT(is_ex_exactly_of_type(t2,color)&&
+                           (ex_to_color(t2).type==color::color_T)&&
+                           (ex_to_color(t2).seq.size()==1));
+                    coloridx const & idx1=ex_to_coloridx(ex_to_color(t1).seq[0]);
+                    coloridx const & idx2=ex_to_coloridx(ex_to_color(t2).seq[0]);
+                    
+                    if (idx1.is_equal(idx2) && idx1.is_symbolic()) {
+                        exvector S;
+                        for (unsigned k=i+1; k<j; ++k) {
+                            S.push_back(Tvecs[rl][k]);
+                        }
+                        t1=exONE();
+                        t2=exONE();
+                        ex term1=numeric(-1)/numeric(6)*nonsimplified_ncmul(recombine_color_string(
+                                 delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+                        for (unsigned k=i+1; k<j; ++k) {
+                            S.push_back(exONE());
+                        }
+                        t1=color_trace_of_one_representation_label(S);
+                        ex term2=numeric(1)/numeric(2)*nonsimplified_ncmul(recombine_color_string(
+                                 delta8vec,fvec,dvec,Tvecs,ONEvecs,unknownvec));
+                        return simplify_color(term1+term2);
+                    }
+                }
+            }
+        }
+    }
+    
+    // TODO: higher contractions!!!!!!!!!!!!!
+    
+    return e;
+}
+    
+ex simplify_color(ex const & e)
+{
+    // all simplification is done on expanded objects
+    ex e_expanded=e.expand();
+
+    // simplification of sum=sum of simplifications
+    if (is_ex_exactly_of_type(e_expanded,add)) {
+        ex sum=exZERO();
+        for (int i=0; i<e_expanded.nops(); ++i) {
+            sum += simplify_color(e_expanded.op(i));
+        }
+        return sum;
+    }
+
+    // simplification of commutative product=commutative product of simplifications
+    if (is_ex_exactly_of_type(e_expanded,mul)) {
+        ex prod=exONE();
+        for (int i=0; i<e_expanded.nops(); ++i) {
+            prod *= simplify_color(e_expanded.op(i));
+        }
+        return prod;
+    }
+
+    // simplification of noncommutative product: test if everything is color
+    if (is_ex_exactly_of_type(e_expanded,ncmul)) {
+        bool all_color=true;
+        for (int i=0; i<e_expanded.nops(); ++i) {
+            if (!is_ex_exactly_of_type(e_expanded.op(i),color)) {
+                all_color=false;
+                break;
+            }
+        }
+        if (all_color) {
+            return simplify_pure_color_string(e_expanded);
+        }
+    }
+
+    // cannot do anything
+    return e_expanded;
+}
+
+ex brute_force_sum_color_indices(ex const & e)
+{
+    exvector iv_all=e.get_indices();
+    exvector iv_double;
+    
+    // find double symbolic indices
+    if (iv_all.size()<2) return e;
+    for (exvector::const_iterator cit1=iv_all.begin(); cit1!=iv_all.end()-1; ++cit1) {
+        ASSERT(is_ex_of_type(*cit1,coloridx));
+        for (exvector::const_iterator cit2=cit1+1; cit2!=iv_all.end(); ++cit2) {
+            ASSERT(is_ex_of_type(*cit2,coloridx));
+            if (ex_to_coloridx(*cit1).is_symbolic() && 
+                ex_to_coloridx(*cit1).is_equal(ex_to_coloridx(*cit2))) {
+                iv_double.push_back(*cit1);
+                break;
+            }
+        }
+    }
+
+    vector<int> counter;
+    counter.resize(iv_double.size());
+    int l;
+    for (l=0; unsigned(l)<iv_double.size(); ++l) {
+        counter[l]=1;
+    }
+
+    ex sum=exZERO();
+    
+    while (1) {
+        ex term=e;
+        for (l=0; unsigned(l)<iv_double.size(); ++l) {
+            term=term.subs(iv_double[l]==coloridx((unsigned)(counter[l])));
+            //iv_double[l].print(cout);
+            //cout << " " << counter[l] << " ";
+        }
+        //cout << endl;
+        sum += term;
+        
+        // increment counter[]
+        l=iv_double.size()-1;
+        while ((l>=0)&&((++counter[l])>COLOR_EIGHT)) {
+            counter[l]=1;    
+            l--;
+        }
+        if (l<2) { cout << counter[0] << counter[1] << endl; }
+        if (l<0) break;
+    }
+    
+    return sum;
+}
+
+void append_exvector_to_exvector(exvector & dest, exvector const & source)
+{
+    for (exvector::const_iterator cit=source.begin(); cit!=source.end(); ++cit) {
+        dest.push_back(*cit);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ginac/color.h b/ginac/color.h
new file mode 100644 (file)
index 0000000..3237359
--- /dev/null
@@ -0,0 +1,143 @@
+/** @file color.h
+ *
+ *  Interface to GiNaC's color objects. */
+
+#ifndef _COLOR_H_
+#define _COLOR_H_
+
+#include <string>
+#include <vector>
+
+class color;
+
+#include "indexed.h"
+
+#define MAX_REPRESENTATION_LABELS 4
+#define COLOR_EIGHT 8 // N*N-1
+#define COLOR_THREE 3 // N
+
+/** Base class for color object */
+class color : public indexed
+{
+// friends
+
+    friend color color_ONE(unsigned const rl);
+    friend color color_T(ex const & a, unsigned const rl);
+    friend color color_f(ex const & a, ex const & b, ex const & c);
+    friend color color_d(ex const & a, ex const & b, ex const & c);
+    friend ex color_h(ex const & a, ex const & b, ex const & c);
+    friend color color_delta8(ex const & a, ex const & b);
+    friend unsigned subs_index_in_exvector(exvector & v, ex const & is, ex const & ir);
+    friend void split_color_string_in_parts(exvector const & v, exvector & delta8vec,
+                                            exvector & fvec, exvector & dvec,
+                                            vector<exvector> & Tvecs,
+                                            vector<exvector> & ONEvecs,
+                                            exvector & unknownvec);
+    friend exvector recombine_color_string(exvector & delta8vec, exvector & fvec,
+                                           exvector & dvec, vector<exvector> & Tvecs,
+                                           vector<exvector> & ONEvecs, exvector & unknownvec);
+    friend ex color_trace_of_one_representation_label(exvector const & v);
+    friend ex color_trace(exvector const & v, unsigned const rl);
+    friend ex simplify_pure_color_string(ex const & e);
+    friend ex simplify_color(ex const & e);
+
+    
+// types
+
+public:
+    typedef enum { invalid, // not properly constructed by one of the friend functions
+                   color_T,
+                   color_f,
+                   color_d,
+                   color_delta8,
+                   color_ONE
+    } color_types;
+    
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    color();
+    ~color();
+    color(color const & other);
+    color const & operator=(color const & other);
+protected:
+    void copy(color const & other); 
+    void destroy(bool call_parent);
+
+    // other constructors
+protected:
+    color(color_types const t, unsigned const rl=0);
+    color(color_types const t, ex const & i1, unsigned const rl=0);
+    color(color_types const t, ex const & i1, ex const & i2, unsigned const rl=0);
+    color(color_types const t, ex const & i1, ex const & i2, ex const & i3,
+          unsigned const rl=0);
+    color(color_types const t, exvector const & iv, unsigned const rl=0);
+    color(color_types const t, exvector * ivp, unsigned const rl=0);
+    
+    // functions overriding virtual functions from base classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+    ex eval(int level=0) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    ex simplify_ncmul(exvector const & v) const;
+    ex thisexprseq(exvector const & v) const;
+    ex thisexprseq(exvector * vp) const;
+
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+protected:
+    bool all_of_type_coloridx(void) const;
+    
+// member variables
+
+protected:
+    color_types type;
+    unsigned representation_label; // to distiguish independent color matrices coming from separated fermion lines
+};
+
+// global constants
+
+extern const color some_color;
+extern type_info const & typeid_color;
+
+// macros
+
+#define ex_to_color(X) static_cast<color const &>(*(X).bp)
+#define ex_to_nonconst_color(X) static_cast<color &>(*(X).bp)
+
+color color_ONE(unsigned const rl=0);
+color color_T(ex const & a, unsigned const rl=0);
+color color_f(ex const & a, ex const & b, ex const & c);
+color color_d(ex const & a, ex const & b, ex const & c);
+ex color_h(ex const & a, ex const & b, ex const & c);
+color color_delta8(ex const & a, ex const & b);
+void split_color_string_in_parts(exvector const & v, exvector & delta8vec,
+                                 exvector & fvec, exvector & dvec,
+                                 vector<exvector> & Tvecs,
+                                 vector<exvector> & ONEvecs,
+                                 exvector & unknownvec);
+exvector recombine_color_string(exvector & delta8vec, exvector & fvec,
+                                exvector & dvec, vector<exvector> & Tvecs,
+                                vector<exvector> & ONEvecs, exvector & unknownvec);
+ex color_trace_of_one_representation_label(exvector const & v);
+ex color_trace(exvector const & v, unsigned const rl=0);
+ex simplify_pure_color_string(ex const & e);
+ex simplify_color(ex const & e);
+
+ex brute_force_sum_color_indices(ex const & e);
+
+void append_exvector_to_exvector(exvector & dest, exvector const & source);
+
+#endif // ndef _COLOR_H_
+
+
diff --git a/ginac/coloridx.cpp b/ginac/coloridx.cpp
new file mode 100644 (file)
index 0000000..2b12a99
--- /dev/null
@@ -0,0 +1,196 @@
+/** @file coloridx.cpp
+ *
+ *  Implementation of GiNaC's color indices. */
+
+#include <stdexcept>
+
+#include "ginac.h"
+#include "utils.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+coloridx::coloridx()
+{
+    debugmsg("coloridx default constructor",LOGLEVEL_CONSTRUCT);
+    // serial is incremented in idx::idx()
+    name="color"+ToString(serial);
+    tinfo_key=TINFO_COLORIDX;
+}
+
+coloridx::~coloridx() 
+{
+    debugmsg("coloridx destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+coloridx::coloridx(coloridx const & other)
+{
+    debugmsg("coloridx copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+coloridx const & coloridx::operator=(coloridx const & other)
+{
+    debugmsg("coloridx operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void coloridx::copy(coloridx const & other)
+{
+    idx::copy(other);
+}
+
+void coloridx::destroy(bool call_parent)
+{
+    if (call_parent) idx::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+coloridx::coloridx(bool cov) : idx(cov)
+{
+    debugmsg("coloridx constructor from bool",LOGLEVEL_CONSTRUCT);
+    // serial is incremented in idx::idx(bool)
+    name="color"+ToString(serial);
+    tinfo_key=TINFO_COLORIDX;
+}
+
+coloridx::coloridx(string const & n, bool cov) : idx(n,cov)
+{
+    debugmsg("coloridx constructor from string,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_COLORIDX;
+}
+
+coloridx::coloridx(char const * n, bool cov) : idx(n,cov)
+{
+    debugmsg("coloridx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_COLORIDX;
+}
+
+coloridx::coloridx(unsigned const v, bool cov) : idx(v,cov)
+{
+    debugmsg("coloridx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_COLORIDX;
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * coloridx::duplicate() const
+{
+    debugmsg("coloridx duplicate",LOGLEVEL_DUPLICATE);
+    return new coloridx(*this);
+}
+
+void coloridx::printraw(ostream & os) const
+{
+    debugmsg("coloridx printraw",LOGLEVEL_PRINT);
+
+    os << "coloridx(";
+
+    if (symbolic) {
+        os << "symbolic,name=" << name;
+    } else {
+        os << "non symbolic,value=" << value;
+    }
+
+    if (covariant) {
+        os << ",covariant";
+    } else {
+        os << ",contravariant";
+    }
+
+    os << ",serial=" << serial;
+    os << ",hash=" << hashvalue << ",flags=" << flags;
+    os << ")";
+}
+
+void coloridx::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("coloridx printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "coloridx: ";
+
+    if (symbolic) {
+        os << "symbolic,name=" << name;
+    } else {
+        os << "non symbolic,value=" << value;
+    }
+
+    if (covariant) {
+        os << ",covariant";
+    } else {
+        os << ",contravariant";
+    }
+
+    os << ", serial=" << serial
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void coloridx::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("coloridx print",LOGLEVEL_PRINT);
+
+    if (covariant) {
+        os << "_";
+    } else {
+        os << "~";
+    }
+    if (symbolic) {
+        os << name;
+    } else {
+        os << value;
+    }
+}
+
+bool coloridx::info(unsigned inf) const
+{
+    if (inf==info_flags::coloridx) return true;
+    return idx::info(inf);
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// none
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const coloridx some_coloridx;
+type_info const & typeid_coloridx=typeid(some_coloridx);
+
+
+
diff --git a/ginac/coloridx.h b/ginac/coloridx.h
new file mode 100644 (file)
index 0000000..92e6b1f
--- /dev/null
@@ -0,0 +1,63 @@
+/** @file coloridx.h
+ *
+ *  Interface to GiNaC's color indices. */
+
+#ifndef _COLORIDX_H_
+#define _COLORIDX_H_
+
+#include <string>
+#include <vector>
+
+#include "idx.h"
+
+class coloridx : public idx
+{
+    friend class color;
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    coloridx();
+    ~coloridx();
+    coloridx (coloridx const & other);
+    coloridx const & operator=(coloridx const & other);
+protected:
+    void copy(coloridx const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    explicit coloridx(bool cov);
+    explicit coloridx(string const & n, bool cov=false);
+    explicit coloridx(char const * n, bool cov=false);
+    explicit coloridx(unsigned const v, bool cov=false); 
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+
+    // new virtual functions which can be overridden by derived classes
+    // none
+
+    // non-virtual functions in this class
+    // none
+
+    // member variables
+    // none
+};
+
+// global constants
+
+extern const coloridx some_coloridx;
+extern type_info const & typeid_coloridx;
+
+// macros
+
+#define ex_to_coloridx(X) (static_cast<coloridx const &>(*(X).bp))
+
+#endif // ndef _COLORIDX_H_
diff --git a/ginac/constant.cpp b/ginac/constant.cpp
new file mode 100644 (file)
index 0000000..a1cc1ef
--- /dev/null
@@ -0,0 +1,143 @@
+/** @file constant.cpp
+ *
+ *  Implementation of GiNaC's constant types and some special constants. */
+
+#include <string>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+constant::~constant()
+{
+    debugmsg("constant destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+constant::constant(constant const & other)
+{
+    debugmsg("constant copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+// protected
+
+void constant::copy(constant const & other)
+{
+    basic::copy(other);
+    name=other.name;
+    serial=other.serial;
+    ef=other.ef;
+    if (other.number != 0) {
+        number = new numeric(*other.number);
+    } else {
+        number = 0;
+    }
+    fct_assigned=other.fct_assigned;
+}
+
+void constant::destroy(bool call_parent)
+{
+    delete number;
+    if (call_parent)
+        basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+constant::constant(string const & initname, ex (*efun)()) :
+    basic(TINFO_CONSTANT), name(initname), ef(efun),
+    number(0), fct_assigned(true), serial(next_serial++)
+{
+    debugmsg("constant constructor from string, function",LOGLEVEL_CONSTRUCT);
+}
+
+constant::constant(string const & initname, numeric const & initnumber) :
+    basic(TINFO_CONSTANT), name(initname), ef(0),
+    number(new numeric(initnumber)), fct_assigned(false), serial(next_serial++)
+{
+    debugmsg("constant constructor from string, numeric",LOGLEVEL_CONSTRUCT);
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * constant::duplicate() const
+{
+    debugmsg("constant duplicate",LOGLEVEL_DUPLICATE);
+    return new constant(*this);
+}
+
+ex constant::evalf(int level) const
+{
+    if (fct_assigned) {
+        return ef();
+    } else if (number != 0) {
+        return *number;
+    }
+    return *this;
+}
+
+// protected
+
+int constant::compare_same_type(basic const & other) const
+{
+    ASSERT(is_exactly_of_type(other, constant));
+    // constant const & o=static_cast<constant &>(const_cast<basic &>(other));
+    // return name.compare(o.name);
+    const constant *o = static_cast<const constant *>(&other);
+    if (serial==o->serial) return 0;
+    return serial < o->serial ? -1 : 1;
+}
+
+bool constant::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_exactly_of_type(other, constant));
+    const constant *o = static_cast<const constant *>(&other);
+    return serial==o->serial;
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// none
+
+//////////
+// static member variables
+//////////
+
+unsigned constant::next_serial=0;
+
+//////////
+// global constants
+//////////
+
+const constant some_constant("",0);
+type_info const & typeid_constant=typeid(some_constant);
+
+/**  Pi. (3.14159...)  Diverts straight into CLN for evalf(). */
+const constant Pi("Pi", PiEvalf);
+/** Catalan's constant. (0.91597...)  Diverts straight into CLN for evalf(). */
+const constant EulerGamma("EulerGamma", EulerGammaEvalf);
+/** Euler's constant. (0.57721...)  Sometimes called Euler-Mascheroni constant.
+ *  Diverts straight into CLN for evalf(). */
+const constant Catalan("Catalan", CatalanEvalf);
diff --git a/ginac/constant.h b/ginac/constant.h
new file mode 100644 (file)
index 0000000..ef7e8c8
--- /dev/null
@@ -0,0 +1,77 @@
+/** @file constant.h
+ *
+ *  Interface to GiNaC's constant types and some special constants. */
+
+#ifndef _CONSTANT_H_
+#define _CONSTANT_H_
+
+#include <string>
+
+class constant;
+
+#include "ex.h"
+#include "numeric.h"
+
+/** This class holds constants, symbols with specific numerical value. Each
+ *  object of this class must either provide their own function to evaluate it
+ *  to class numeric or provide the constant as a numeric (if it's an exact
+ *  number). */
+class constant : public basic
+{
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    ~constant();
+    constant(constant const & other);
+    // constant const & operator=(constant const & other); /* it's pervert! */
+protected:
+    void copy(constant const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    constant(string const & initname, ex (*efun)()=0);
+    constant(string const & initname, numeric const & initnumber);
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    ex evalf(int level=0) const;
+    ex diff(symbol const & s) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+
+    // non-virtual functions in this class
+    // none
+
+// member variables
+
+private:
+    string name;
+    ex (*ef)();
+    numeric * number;
+    bool fct_assigned;
+    unsigned serial;  //!< unique serial number for comparision
+    static unsigned next_serial;
+};
+
+// global constants
+
+extern const constant some_constant;
+extern type_info const & typeid_constant;
+
+// extern const numeric I;
+extern const constant Pi;
+extern const constant Catalan;
+extern const constant EulerGamma;
+
+#endif // ndef _CONSTANT_H_
diff --git a/ginac/container.pl b/ginac/container.pl
new file mode 100755 (executable)
index 0000000..d7b860b
--- /dev/null
@@ -0,0 +1,816 @@
+#!/usr/bin/perl -w
+
+if ($#ARGV!=0) {
+    die 'usage: container.pl type (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';
+}
+
+#$type='lst';
+#$type='exprseq';
+
+if ($type eq 'exprseq') {
+
+    # settings for exprseq
+    $CONTAINER="exprseq";
+    $STLHEADER="vector";
+    $reserve=1;
+    $prepend=0;
+    $let_op=0;
+    $open_bracket='(';
+    $close_bracket=')';
+    
+} elsif ($type eq 'lst') {
+    # settings for lst
+    $CONTAINER="lst";
+    $STLHEADER="list";
+    $reserve=0;
+    $prepend=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(ex const & b);
+END_OF_PREPEND_INTERFACE
+
+    $PREPEND_IMPLEMENTATION=<<END_OF_PREPEND_IMPLEMENTATION;
+${CONTAINER} & ${CONTAINER}::prepend(ex const & b)
+{
+    ensure_if_modifiable();
+    seq.push_front(b);
+    return *this;
+}
+END_OF_PREPEND_IMPLEMENTATION
+} else {
+    $PREPEND_INTERFACE="    // no prepend possible for ${CONTAINER}";
+    $PREPEND_IMPLEMENTATION="";
+}
+
+if ($let_op) {
+    $LET_OP_IMPLEMENTATION=<<END_OF_LET_OP_IMPLEMENTATION
+ex & ${CONTAINER}::let_op(int const i)
+{
+    ASSERT(i>=0);
+    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";
+}
+
+$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}
+ *                        \$let_op=${let_op}
+ *                        \$open_bracket=${open_bracket}
+ *                        \$close_bracket=${close_bracket} */
+
+#ifndef _${CONTAINER_UC}_H_
+#define _${CONTAINER_UC}_H_
+
+#include <${STLHEADER}>
+
+#include <ginac/ginac.h>
+
+typedef ${STLHEADER}<ex> ${STLT};
+
+class ${CONTAINER} : public basic
+{
+
+public:
+    ${CONTAINER}();
+    ~${CONTAINER}();
+    ${CONTAINER}(${CONTAINER} const & other);
+    ${CONTAINER} const & operator=(${CONTAINER} const & other);
+protected:
+    void copy(${CONTAINER} const & other);
+    void destroy(bool call_parent);
+
+public:
+    ${CONTAINER}(${STLT} const & s, bool discardable=0);
+    ${CONTAINER}(${STLT} * vp); // vp will be deleted
+    explicit ${CONTAINER}(ex const & e1);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2, ex const & e3);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8, ex const & e9);
+    explicit ${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8, ex const & e9,
+             ex const &e10);
+
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printtree(ostream & os, unsigned indent) const;
+    bool info(unsigned inf) const;
+    int nops() const;
+    ex & let_op(int const i);
+    ex expand(unsigned options=0) const;
+    bool has(ex const & 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(symbol const & s) const;
+    ex subs(lst const & ls, lst const & lr) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+
+    // new virtual functions which can be overridden by derived classes
+public:
+    virtual ${CONTAINER} & append(ex const & b);
+${PREPEND_INTERFACE}
+protected:
+    virtual void printseq(ostream & os, 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} evalfchildren(int level) const;
+    ${STLT} normalchildren(int level) const;
+    ${STLT} diffchildren(symbol const & s) const;
+    ${STLT} * subschildren(lst const & ls, lst const & lr) const;
+
+protected:
+    ${STLT} seq;
+    static unsigned precedence;
+};
+
+// global constants
+
+extern const ${CONTAINER} some_${CONTAINER};
+extern type_info const & typeid_${CONTAINER};
+
+// macros
+
+#define ex_to_${CONTAINER}(X) (static_cast<${CONTAINER} const &>(*(X).bp))
+
+#endif // ndef _${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} */
+
+#include <iostream>
+#include <stdexcept>
+
+#include "ginac.h"
+
+${RESERVE_IMPLEMENTATION}
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+${CONTAINER}::${CONTAINER}() : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} default constructor",LOGLEVEL_CONSTRUCT);
+}
+
+${CONTAINER}::~${CONTAINER}()
+{
+    debugmsg("${CONTAINER} destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+${CONTAINER}::${CONTAINER}(${CONTAINER} const & other)
+{
+    debugmsg("${CONTAINER} copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+${CONTAINER} const & ${CONTAINER}::operator=(${CONTAINER} const & other)
+{
+    debugmsg("${CONTAINER} operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void ${CONTAINER}::copy(${CONTAINER} const & other)
+{
+    basic::copy(other);
+    seq=other.seq;
+}
+
+void ${CONTAINER}::destroy(bool call_parent)
+{
+    seq.clear();
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+${CONTAINER}::${CONTAINER}(${STLT} const & s, bool discardable) :  basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from ${STLT}",
+             LOGLEVEL_CONSTRUCT);
+    if (discardable) {
+        seq.swap(const_cast<${STLT} &>(s));
+    } else {
+        seq=s;
+    }
+}
+
+${CONTAINER}::${CONTAINER}(${STLT} * vp) : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from ${STLT} *",LOGLEVEL_CONSTRUCT);
+    ASSERT(vp!=0);
+    seq.swap(*vp);
+    delete vp;
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1) :  basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 1 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,1);
+    seq.push_back(e1);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2) : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 2 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,2);
+    seq.push_back(e1);
+    seq.push_back(e2);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2, ex const & e3)
+    : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 3 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,3);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4) : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 4 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,4);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5) : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 5 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,5);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6)
+    : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 6 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,6);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7) : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 7 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,7);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8) : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 8 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,8);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8, ex const & e9)
+    : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 9 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,9);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+    seq.push_back(e9);
+}
+
+${CONTAINER}::${CONTAINER}(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8, ex const & e9,
+                     ex const &e10)
+    : basic(TINFO_${CONTAINER_UC})
+{
+    debugmsg("${CONTAINER} constructor from 10 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,10);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+    seq.push_back(e9);
+    seq.push_back(e10);
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * ${CONTAINER}::duplicate() const
+{
+    debugmsg("${CONTAINER} duplicate",LOGLEVEL_DUPLICATE);
+    return new ${CONTAINER}(*this);
+}
+
+void ${CONTAINER}::printraw(ostream & os) const
+{
+    debugmsg("${CONTAINER} printraw",LOGLEVEL_PRINT);
+
+    os << "${CONTAINER}(";
+    for (${STLT}::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).bp->printraw(os);
+        os << ",";
+    }
+    os << ")";
+}
+
+void ${CONTAINER}::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("${CONTAINER} print",LOGLEVEL_PRINT);
+    // always print brackets around seq, ignore upper_precedence
+    printseq(os,'${open_bracket}',',','${close_bracket}',precedence,precedence+1);
+}
+
+void ${CONTAINER}::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("${CONTAINER} printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "type=" << typeid(*this).name()
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags
+       << ", nops=" << nops() << endl;
+    for (${STLT}::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).printtree(os,indent+delta_indent);
+    }
+    os << string(indent+delta_indent,' ') << "=====" << endl;
+}
+
+// ${CONTAINER}::info() will be implemented by user elsewhere";
+
+int ${CONTAINER}::nops() const
+{
+    return seq.size();
+}
+
+${LET_OP_IMPLEMENTATION}
+
+ex ${CONTAINER}::expand(unsigned options) const
+{
+    ${STLT} s;
+    RESERVE(s,seq.size());
+    for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).expand(options));
+    }
+
+    return this${CONTAINER}(s);
+}
+
+// a ${CONTAINER} 'has' an expression if it is this expression itself or a child 'has' it
+
+bool ${CONTAINER}::has(ex const & other) const
+{
+    ASSERT(other.bp!=0);
+    if (is_equal(*other.bp)) return true;
+    for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        if ((*it).has(other)) return true;
+    }
+    return false;
+}
+
+ex ${CONTAINER}::eval(int level) const
+{
+    if (level==1) {
+        return this->hold();
+    }
+    return this${CONTAINER}(evalchildren(level));
+}
+
+ex ${CONTAINER}::evalf(int level) const
+{
+    return this${CONTAINER}(evalfchildren(level));
+}
+
+/** Implementation of ex::normal() for ${CONTAINER}s. It normalizes the arguments
+ *  and replaces the ${CONTAINER} by a temporary symbol.
+ *  \@see ex::normal */
+ex ${CONTAINER}::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    ex n=this${CONTAINER}(normalchildren(level));
+    return n.bp->basic::normal(sym_lst,repl_lst,level);
+}
+
+ex ${CONTAINER}::diff(symbol const & s) const
+{
+    return this${CONTAINER}(diffchildren(s));
+}
+
+ex ${CONTAINER}::subs(lst const & ls, lst const & lr) const
+{
+    ${STLT} * vp=subschildren(ls,lr);
+    if (vp==0) {
+        return *this;
+    }
+    return this${CONTAINER}(vp);
+}
+
+// protected
+
+int ${CONTAINER}::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,${CONTAINER}));
+    ${CONTAINER} const & o=static_cast<${CONTAINER} const &>
+                                    (const_cast<basic &>(other));
+    int cmpval;
+    ${STLT}::const_iterator it1=seq.begin();
+    ${STLT}::const_iterator it2=o.seq.begin();
+
+    for (; (it1!=seq.end())&&(it2!=o.seq.end()); ++it1, ++it2) {
+        cmpval=(*it1).compare(*it2);
+        if (cmpval!=0) return cmpval;
+    }
+
+    if (it1==seq.end()) {
+        return (it2==o.seq.end() ? 0 : -1);
+    }
+
+    return 1;
+}
+
+bool ${CONTAINER}::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,${CONTAINER}));
+    ${CONTAINER} const & o=static_cast<${CONTAINER} const &>
+                                    (const_cast<basic &>(other));
+    if (seq.size()!=o.seq.size()) return false;
+
+    ${STLT}::const_iterator it1=seq.begin();
+    ${STLT}::const_iterator it2=o.seq.begin();
+
+    for (; it1!=seq.end(); ++it1, ++it2) {
+       if (!(*it1).is_equal(*it2)) return false;
+    }
+
+    return true;
+}
+
+unsigned ${CONTAINER}::return_type(void) const
+{
+    return return_types::noncommutative_composite;
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// public
+
+${CONTAINER} & ${CONTAINER}::append(ex const & b)
+{
+    ensure_if_modifiable();
+    seq.push_back(b);
+    return *this;
+}
+
+${PREPEND_IMPLEMENTATION}
+
+// protected
+
+void ${CONTAINER}::printseq(ostream & os, char openbracket, char delim,
+                         char closebracket, unsigned this_precedence,
+                         unsigned upper_precedence) const
+{
+    if (this_precedence<=upper_precedence) os << openbracket;
+    if (seq.size()!=0) {
+        ${STLT}::const_iterator it,it_last;
+        it=seq.begin();
+        it_last=seq.end();
+        --it_last;
+        for (; it!=it_last; ++it) {
+            (*it).bp->print(os,this_precedence);
+            os << delim;
+        }
+        (*it).bp->print(os,this_precedence);
+    }
+    if (this_precedence<=upper_precedence) os << 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();
+    ${STLT}::const_iterator it_last=it;
+    for (++it; it!=seq.end(); it_last=it, ++it) {
+        if ((*it_last).compare(*it)>0) {
+            if ((*it_last).compare(*it)>0) {
+                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;
+    for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).eval(level));
+    }
+    return s;
+}
+
+${STLT} ${CONTAINER}::evalfchildren(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;
+    for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).evalf(level));
+    }
+    return s;
+}
+
+${STLT} ${CONTAINER}::normalchildren(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;
+    for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).normal(level));
+    }
+    return s;
+}
+
+${STLT} ${CONTAINER}::diffchildren(symbol const & y) const
+{
+    ${STLT} s;
+    RESERVE(s,seq.size());
+    for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).diff(y));
+    }
+    return s;
+}
+
+/* obsolete subschildren
+${STLT} ${CONTAINER}::subschildren(lst const & ls, lst const & lr) const
+{
+    ${STLT} s;
+    RESERVE(s,seq.size());
+    for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).subs(ls,lr));
+    }
+    return s;
+}
+*/
+
+${STLT} * ${CONTAINER}::subschildren(lst const & ls, lst const & lr) 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 last=seq.end();
+    ${STLT}::const_iterator cit=seq.begin();
+    while (cit!=last) {
+        ex const & subsed_ex=(*cit).subs(ls,lr);
+        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!=last) {
+                s->push_back((*cit2).subs(ls,lr));
+                ++cit2;
+           }
+            return s;
+        }
+        ++cit;
+    }
+    
+    return 0; // nothing has changed
+}
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned ${CONTAINER}::precedence=10;
+
+//////////
+// global constants
+//////////
+
+const ${CONTAINER} some_${CONTAINER};
+type_info const & typeid_${CONTAINER}=typeid(some_${CONTAINER});
+
+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";
diff --git a/ginac/debugmsg.h b/ginac/debugmsg.h
new file mode 100644 (file)
index 0000000..caf8bcb
--- /dev/null
@@ -0,0 +1,42 @@
+/** @file debugmsg.h
+ *
+ *  Utilities needed for debugging only. */
+
+#ifndef _DEBUGMSG_H_
+#define _DEBUGMSG_H_
+
+#ifdef _DEBUG
+#define VERBOSE
+#define DOASSERT (VERBOSE||DEBUG)
+#endif
+
+#define LOGLEVEL_CONSTRUCT          0x0001
+#define LOGLEVEL_DESTRUCT           0x0002
+#define LOGLEVEL_ASSIGNMENT         0x0004
+#define LOGLEVEL_DUPLICATE          0x0008
+#define LOGLEVEL_PRINT              0x0010
+#define LOGLEVEL_OPERATOR           0x0020
+#define LOGLEVEL_MEMBER_FUNCTION    0x4000
+#define LOGLEVEL_NONMEMBER_FUNCTION 0x8000
+#define LOGLEVEL_ALL                0xffff
+
+#define LOGMASK (LOGLEVEL_PRINT)
+// #define LOGMASK (LOGLEVEL_PRINT | LOGLEVEL_ASSIGNMENT | LOGLEVEL_OPERATOR | LOGLEVEL_DUPLICATE | LOGLEVEL_OPERATOR | LOGLEVEL_MEMBER_FUNCTION | LOGLEVEL_NONMEMBER_FUNCTION )
+
+#include <assert.h>
+#include <iostream>
+
+#ifdef VERBOSE
+#define debugmsg(msg, loglevel) if ((loglevel) & ~LOGMASK) clog << (msg) << endl;
+#else
+#define debugmsg(msg, loglevel)
+#endif // def VERBOSE
+
+#ifdef DOASSERT
+#define ASSERT(X) assert(X)
+#else
+#define ASSERT(X) ((void)0)
+#endif
+
+#endif // ndef _DEBUGMSG_H_
+
diff --git a/ginac/diff.cpp b/ginac/diff.cpp
new file mode 100644 (file)
index 0000000..b8ef4c5
--- /dev/null
@@ -0,0 +1,208 @@
+/** @file diff.cpp
+ *
+ *  Implementation of symbolic differentiation in all of GiNaC's classes. */
+
+#include <stdexcept>
+
+#include "ginac.h"
+
+/** Default implementation of ex::diff(). It prints and error message and returns a fail object.
+ *  @see ex::diff */
+ex basic::diff(symbol const & s) const
+{
+    throw(std::logic_error("differentiation not supported by this type"));
+}
+
+
+/** Implementation of ex::diff() for a numeric. It always returns 0.
+ *
+ *  @see ex::diff */
+ex numeric::diff(symbol const & s) const
+{
+    return exZERO();
+}
+
+
+/** Implementation of ex::diff() for single differentiation of a symbol.
+ *  It returns 1 or 0.
+ *
+ *  @see ex::diff */
+ex symbol::diff(symbol const & s) const
+{
+    if (compare_same_type(s)) {
+        return exZERO();
+    } else {
+        return exONE();
+    }
+}
+
+/** Implementation of ex::diff() for a constant. It always returns 0.
+ *
+ *  @see ex::diff */
+ex constant::diff(symbol const & s) const
+{
+    return exZERO();
+}
+
+/** Implementation of ex::diff() for multiple differentiation of a symbol.
+ *  It returns the symbol, 1 or 0.
+ *
+ *  @param nth order of differentiation
+ *  @see ex::diff */
+ex symbol::diff(symbol const & s, unsigned nth) const
+{
+    if (compare_same_type(s)) {
+        switch (nth) {
+        case 0:
+            return s;
+            break;
+        case 1:
+            return exONE();
+            break;
+        default:
+            return exZERO();
+        }
+    } else {
+        return exONE();
+    }
+}
+
+
+/** Implementation of ex::diff() for an indexed object. It always returns 0.
+ *  @see ex::diff */
+ex indexed::diff(symbol const & s) const
+{
+        return exZERO();
+}
+
+
+/** Implementation of ex::diff() for an expairseq. It differentiates all elements of the sequence.
+ *  @see ex::diff */
+ex expairseq::diff(symbol const & s) const
+{
+    return thisexpairseq(diffchildren(s),overall_coeff);
+}
+
+
+/** Implementation of ex::diff() for a sum. It differentiates each term.
+ *  @see ex::diff */
+ex add::diff(symbol const & s) const
+{
+    // D(a+b+c)=D(a)+D(b)+D(c)
+    return (new add(diffchildren(s)))->setflag(status_flags::dynallocated);
+}
+
+
+/** Implementation of ex::diff() for a product. It applies the product rule.
+ *  @see ex::diff */
+ex mul::diff(symbol const & s) const
+{
+    exvector new_seq;
+    new_seq.reserve(seq.size());
+
+    // D(a*b*c)=D(a)*b*c+a*D(b)*c+a*b*D(c)
+    for (unsigned i=0; i!=seq.size(); i++) {
+        epvector sub_seq=seq;
+        sub_seq[i] = split_ex_to_pair(sub_seq[i].coeff*
+                                      power(sub_seq[i].rest,sub_seq[i].coeff-1)*
+                                      sub_seq[i].rest.diff(s));
+        new_seq.push_back((new mul(sub_seq,overall_coeff))->setflag(status_flags::dynallocated));
+    }
+    return (new add(new_seq))->setflag(status_flags::dynallocated);
+}
+
+
+/** Implementation of ex::diff() for a non-commutative product. It always returns 0.
+ *  @see ex::diff */
+ex ncmul::diff(symbol const & s) const
+{
+    return exZERO();
+}
+
+
+/** Implementation of ex::diff() for a power.
+ *  @see ex::diff */
+ex power::diff(symbol const & s) const
+{
+    if (exponent.info(info_flags::real)) {
+        // D(b^r) = r * b^(r-1) * D(b) (faster than the formula below)
+        return mul(mul(exponent, power(basis, exponent - exONE())), basis.diff(s));
+    } else {
+        // D(b^e) = b^e * (D(e)*ln(b) + e*D(b)/b)
+        return mul(power(basis, exponent),
+                   add(mul(exponent.diff(s), log(basis)),
+                       mul(mul(exponent, basis.diff(s)), power(basis, -1))));
+    }
+}
+
+
+/** Implementation of ex::diff() for functions. It applies the chain rule,
+ *  except for the Order term function.
+ *  @see ex::diff */
+ex function::diff(symbol const & s) const
+{
+    exvector new_seq;
+
+    if (serial == function_index_Order) {
+
+        // Order Term function only differentiates the argument
+        return Order(seq[0].diff(s));
+
+    } else {
+
+        // Chain rule
+        for (unsigned i=0; i!=seq.size(); i++) {
+            new_seq.push_back(mul(pdiff(i), seq[i].diff(s)));
+        }
+    }
+    return add(new_seq);
+}
+
+
+/** Implementation of ex::diff() for a power-series. It treats the series as a polynomial.
+ *  @see ex::diff */
+ex series::diff(symbol const & s) const
+{
+    if (s == var) {
+        epvector new_seq;
+        epvector::const_iterator it = seq.begin(), itend = seq.end();
+        
+        //!! coeff might depend on var
+        while (it != itend) {
+            if (is_order_function(it->rest)) {
+                new_seq.push_back(expair(it->rest, it->coeff - 1));
+            } else {
+                ex c = it->rest * it->coeff;
+                if (!c.is_zero())
+                    new_seq.push_back(expair(c, it->coeff - 1));
+            }
+            it++;
+        }
+        return series(var, point, new_seq);
+    } else {
+        return *this;
+    }
+}
+
+
+/** Compute partial derivative of an expression.
+ *
+ *  @param s  symbol by which the expression is derived
+ *  @param nth  order of derivative (default 1)
+ *  @return partial derivative as a new expression */
+
+ex ex::diff(symbol const & s, unsigned nth) const
+{
+    ASSERT(bp!=0);
+
+    if ( nth==0 ) {
+        return *this;
+    }
+
+    ex ndiff = bp->diff(s);
+    while ( nth>1 ) {
+        ndiff = ndiff.diff(s);
+        --nth;
+    }
+    return ndiff;
+}
diff --git a/ginac/ex.cpp b/ginac/ex.cpp
new file mode 100644 (file)
index 0000000..7cb0c6f
--- /dev/null
@@ -0,0 +1,490 @@
+/** @file ex.cpp
+ *
+ *  Implementation of GiNaC's light-weight expression handles. */
+
+#include <iostream>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+#ifndef INLINE_EX_CONSTRUCTORS
+
+ex::ex() : bp(exZERO().bp)
+{
+    debugmsg("ex default constructor",LOGLEVEL_CONSTRUCT);
+    ASSERT(exZERO().bp!=0);
+    ASSERT(exZERO().bp->flags & status_flags::dynallocated);
+    ASSERT(bp!=0);
+    ++bp->refcount;
+}
+
+ex::~ex()
+{
+    debugmsg("ex destructor",LOGLEVEL_DESTRUCT);
+    ASSERT(bp!=0);
+    ASSERT(bp->flags & status_flags::dynallocated);
+    if (--bp->refcount == 0) {
+        delete bp;
+    }
+}
+
+ex::ex(ex const & other) : bp(other.bp)
+{
+    debugmsg("ex copy constructor",LOGLEVEL_CONSTRUCT);
+    ASSERT(bp!=0);
+    ASSERT((bp->flags) & status_flags::dynallocated);
+    ++bp->refcount;
+}
+
+ex const & ex::operator=(ex const & other)
+{
+    debugmsg("ex operator=",LOGLEVEL_ASSIGNMENT);
+    ASSERT(bp!=0);
+    ASSERT(bp->flags & status_flags::dynallocated);
+    ASSERT(other.bp!=0);
+    ASSERT(other.bp->flags & status_flags::dynallocated);
+    ++other.bp->refcount;
+    basic * tmpbp=other.bp;
+    if (--bp->refcount==0) {
+            delete bp;
+    }
+    bp=tmpbp;
+    return *this;
+}
+
+#endif // ndef INLINE_EX_CONSTRUCTORS
+
+//////////
+// other constructors
+//////////
+
+// public
+
+#ifndef INLINE_EX_CONSTRUCTORS
+ex::ex(basic const & other)
+{
+    debugmsg("ex constructor from basic",LOGLEVEL_CONSTRUCT);
+    construct_from_basic(other);
+}
+#endif
+
+ex::ex(int const i)
+{
+    debugmsg("ex constructor from int",LOGLEVEL_CONSTRUCT);
+    construct_from_basic(numeric(i));
+}
+
+ex::ex(unsigned int const i)
+{
+    debugmsg("ex constructor from unsigned int",LOGLEVEL_CONSTRUCT);
+    construct_from_basic(numeric(i));
+}
+
+ex::ex(long const i)
+{
+    debugmsg("ex constructor from long",LOGLEVEL_CONSTRUCT);
+    construct_from_basic(numeric(i));
+}
+
+ex::ex(unsigned long const i)
+{
+    debugmsg("ex constructor from unsigned long",LOGLEVEL_CONSTRUCT);
+    construct_from_basic(numeric(i));
+}
+
+ex::ex(double const d)
+{
+    debugmsg("ex constructor from double",LOGLEVEL_CONSTRUCT);
+    construct_from_basic(numeric(d));
+}
+    
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// none
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+
+void ex::swap(ex & other)
+{
+    debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
+
+    ASSERT(bp!=0);
+    ASSERT(bp->flags & status_flags::dynallocated);
+    ASSERT(other.bp!=0);
+    ASSERT(other.bp->flags & status_flags::dynallocated);
+    
+    basic * tmpbp=bp;
+    bp=other.bp;
+    other.bp=tmpbp;
+}
+
+bool ex::info(unsigned inf) const
+{
+    if (inf == info_flags::normal_form) {
+
+    // Polynomials are in normal form
+    if (info(info_flags::polynomial))
+        return true;
+
+    // polynomial^(-int) is in normal form
+    if (is_ex_exactly_of_type(*this, power))
+        return op(1).info(info_flags::negint);
+
+    // polynomial^(int) * polynomial^(int) * ... is in normal form
+    if (!is_ex_exactly_of_type(*this, mul))
+        return false;
+    for (int i=0; i<nops(); i++) {
+        if (is_ex_exactly_of_type(op(i), power)) {
+            if (!op(i).op(1).info(info_flags::integer))
+                return false;
+            if (!op(i).op(0).info(info_flags::polynomial))
+                return false;
+        } else
+            if (!op(i).info(info_flags::polynomial))
+                return false;
+    }
+    return true;
+    } else {
+        return bp->info(inf);
+    }
+}
+
+int ex::nops() const
+{
+    ASSERT(bp!=0);
+    return bp->nops();
+}
+
+ex ex::expand(unsigned options) const
+{
+    ASSERT(bp!=0);
+    return bp->expand(options);
+}
+
+bool ex::has(ex const & other) const
+{
+    ASSERT(bp!=0);
+    return bp->has(other);
+}
+
+int ex::degree(symbol const & s) const
+{
+    ASSERT(bp!=0);
+    return bp->degree(s);
+}
+
+int ex::ldegree(symbol const & s) const
+{
+    ASSERT(bp!=0);
+    return bp->ldegree(s);
+}
+
+ex ex::coeff(symbol const & s, int const n) const
+{
+    ASSERT(bp!=0);
+    return bp->coeff(s,n);
+}
+
+ex ex::numer(bool normalize) const
+{
+    ex n;
+    if (normalize && !info(info_flags::normal_form))
+        n = normal();
+    else
+        n = *this;
+
+    // polynomial
+    if (n.info(info_flags::polynomial))
+        return n;
+
+    // something^(-int)
+    if (is_ex_exactly_of_type(n, power) && n.op(1).info(info_flags::negint))
+        return exONE();
+
+    // something^(int) * something^(int) * ...
+    if (!is_ex_exactly_of_type(n, mul))
+        return n;
+    ex res = exONE();
+    for (int i=0; i<n.nops(); i++) {
+        if (!is_ex_exactly_of_type(n.op(i), power) || !n.op(i).op(1).info(info_flags::negint))
+            res *= n.op(i);
+    }
+    return res;
+}
+
+ex ex::denom(bool normalize) const
+{
+    ex n;
+    if (normalize && !info(info_flags::normal_form))
+        n = normal();
+    else
+        n = *this;
+
+    // polynomial
+    if (n.info(info_flags::polynomial))
+        return exONE();
+
+    // something^(-int)
+    if (is_ex_exactly_of_type(n, power) && n.op(1).info(info_flags::negint))
+        return power(n.op(0), -(n.op(1)));
+
+    // something^(int) * something^(int) * ...
+    if (!is_ex_exactly_of_type(n, mul))
+        return exONE();
+    ex res = exONE();
+    for (int i=0; i<n.nops(); i++) {
+        if (is_ex_exactly_of_type(n.op(i), power) && n.op(i).op(1).info(info_flags::negint))
+            res *= power(n.op(i), -1);
+    }
+    return res;
+}
+
+ex ex::collect(symbol const & s) const
+{
+    ASSERT(bp!=0);
+    return bp->collect(s);
+}
+
+ex ex::eval(int level) const
+{
+    ASSERT(bp!=0);
+    return bp->eval(level);
+}
+
+ex ex::evalf(int level) const
+{
+    ASSERT(bp!=0);
+    return bp->evalf(level);
+}
+
+ex ex::subs(lst const & ls, lst const & lr) const
+{
+    ASSERT(bp!=0);
+    return bp->subs(ls,lr);
+}
+
+ex ex::subs(ex const & e) const
+{
+    ASSERT(bp!=0);
+    return bp->subs(e);
+}
+
+exvector ex::get_indices(void) const
+{
+    ASSERT(bp!=0);
+    return bp->get_indices();
+}
+
+ex ex::simplify_ncmul(exvector const & v) const
+{
+    ASSERT(bp!=0);
+    return bp->simplify_ncmul(v);
+}
+
+ex ex::operator[](ex const & index) const
+{
+    debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
+    ASSERT(bp!=0);
+    return (*bp)[index];
+}
+
+ex ex::operator[](int const i) const
+{
+    debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
+    ASSERT(bp!=0);
+    return (*bp)[i];
+}
+
+ex ex::op(int const i) const
+{
+    debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
+    ASSERT(bp!=0);
+    return bp->op(i);
+}
+
+ex & ex::let_op(int const i)
+{
+    debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
+    makewriteable();
+    ASSERT(bp!=0);
+    return bp->let_op(i);
+}
+
+#ifndef INLINE_EX_CONSTRUCTORS
+int ex::compare(ex const & other) const
+{
+    ASSERT(bp!=0);
+    ASSERT(other.bp!=0);
+    if (bp==other.bp) {
+        // special case: both expression point to same basic, trivially equal
+        return 0; 
+    }
+    return bp->compare(*other.bp);
+}
+#endif // ndef INLINE_EX_CONSTRUCTORS
+
+#ifndef INLINE_EX_CONSTRUCTORS
+bool ex::is_equal(ex const & other) const
+{
+    ASSERT(bp!=0);
+    ASSERT(other.bp!=0);
+    if (bp==other.bp) {
+        // special case: both expression point to same basic, trivially equal
+        return true; 
+    }
+    return bp->is_equal(*other.bp);
+}
+#endif // ndef INLINE_EX_CONSTRUCTORS
+
+unsigned ex::return_type(void) const
+{
+    ASSERT(bp!=0);
+    return bp->return_type();
+}
+
+unsigned ex::return_type_tinfo(void) const
+{
+    ASSERT(bp!=0);
+    return bp->return_type_tinfo();
+}
+
+unsigned ex::gethash(void) const
+{
+    ASSERT(bp!=0);
+    return bp->gethash();
+}
+
+ex ex::exadd(ex const & rh) const
+{
+    return (new add(*this,rh))->setflag(status_flags::dynallocated);
+}
+
+ex ex::exmul(ex const & rh) const
+{
+    return (new mul(*this,rh))->setflag(status_flags::dynallocated);
+}
+
+ex ex::exncmul(ex const & rh) const
+{
+    return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
+}
+
+// private
+
+void ex::makewriteable()
+{
+    debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
+    ASSERT(bp!=0);
+    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;
+    }
+    ASSERT(bp->refcount == 1);
+}    
+
+void ex::construct_from_basic(basic const & other)
+{
+    if ( (other.flags & status_flags::evaluated)==0 ) {
+        // cf. copy constructor
+        ex const & tmpex = other.eval(1); // evaluate only one (top) level
+        bp = tmpex.bp;
+        ASSERT(bp!=0);
+        ASSERT(bp->flags & status_flags::dynallocated);
+        ++bp->refcount;
+        if ((other.flags & status_flags::dynallocated)&&(other.refcount==0)) {
+            delete &const_cast<basic &>(other);
+        }
+    } else {
+        if (other.flags & status_flags::dynallocated) {
+            bp=&const_cast<basic &>(other);
+        } else {
+            bp=other.duplicate();
+            bp->setflag(status_flags::dynallocated);
+        }
+        ASSERT(bp!=0);
+        // bp->clearflag(status_flags::evaluated);
+        ++bp->refcount;
+    }
+    ASSERT(bp!=0);
+    ASSERT(bp->flags & status_flags::dynallocated);
+}
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// functions which are not member functions
+//////////
+
+// none
+
+//////////
+// global functions
+//////////
+
+ex const & exZERO(void)
+{
+    static ex * eZERO=new ex(numZERO());
+    return *eZERO;
+}
+
+ex const & exONE(void)
+{
+    static ex * eONE=new ex(numONE());
+    return *eONE;
+}
+
+ex const & exTWO(void)
+{
+    static ex * eTWO=new ex(numTWO());
+    return *eTWO;
+}
+
+ex const & exTHREE(void)
+{
+    static ex * eTHREE=new ex(numTHREE());
+    return *eTHREE;
+}
+
+ex const & exMINUSONE(void)
+{
+    static ex * eMINUSONE=new ex(numMINUSONE());
+    return *eMINUSONE;
+}
+
+ex const & exHALF(void)
+{
+    static ex * eHALF=new ex(ex(1)/ex(2));
+    return *eHALF;
+}
+
+ex const & exMINUSHALF(void)
+{
+    static ex * eMINUSHALF=new ex(numeric(-1,2));
+    return *eMINUSHALF;
+}
+
diff --git a/ginac/ex.h b/ginac/ex.h
new file mode 100644 (file)
index 0000000..2300627
--- /dev/null
@@ -0,0 +1,269 @@
+/** @file ex.h
+ *
+ *  Interface to GiNaC's light-weight expression handles. */
+
+#ifndef _EX_H_
+#define _EX_H_
+
+#include <iostream>
+
+class ex;
+class expand_options;
+class status_flags;
+
+#include "basic.h"
+#include "debugmsg.h"
+#include "flags.h"
+
+class symbol;
+class lst;
+
+typedef vector<ex> exvector;
+
+// enum definitions
+
+ex const & exZERO(void);
+ex const & exONE(void);
+ex const & exTWO(void);
+ex const & exTHREE(void);
+ex const & exMINUSONE(void);
+ex const & exHALF(void);
+ex const & exMINUSHALF(void);
+
+#define INLINE_EX_CONSTRUCTORS
+
+/** Lightweight interface to GiNaC's symbolic objects. Basically all it does is
+ *  to hold a pointer to the other objects, manage the reference counting and
+ *  provide methods for manipulation of these objects. */
+class ex
+{
+    friend class basic;
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    ex()
+#ifdef INLINE_EX_CONSTRUCTORS
+    : bp(exZERO().bp)
+        {
+            debugmsg("ex default constructor",LOGLEVEL_CONSTRUCT);
+            ASSERT(exZERO().bp!=0);
+            ASSERT(exZERO().bp->flags & status_flags::dynallocated);
+            ASSERT(bp!=0);
+            ++bp->refcount;
+        }
+#else
+;
+#endif // def INLINE_EX_CONSTRUCTORS
+
+    ~ex()
+#ifdef INLINE_EX_CONSTRUCTORS
+        {
+            debugmsg("ex destructor",LOGLEVEL_DESTRUCT);
+            ASSERT(bp!=0);
+            ASSERT(bp->flags & status_flags::dynallocated);
+            if (--bp->refcount == 0) {
+                delete bp;
+            }
+        }
+#else
+;
+#endif // def INLINE_EX_CONSTRUCTORS
+        
+    ex(ex const & other)
+#ifdef INLINE_EX_CONSTRUCTORS
+    : bp(other.bp)
+        {
+            debugmsg("ex copy constructor",LOGLEVEL_CONSTRUCT);
+            ASSERT(bp!=0);
+            ASSERT((bp->flags) & status_flags::dynallocated);
+            ++bp->refcount;
+        }
+#else
+;
+#endif // def INLINE_EX_CONSTRUCTORS
+        
+    ex const & operator=(ex const & other)
+#ifdef INLINE_EX_CONSTRUCTORS
+        {
+            debugmsg("ex operator=",LOGLEVEL_ASSIGNMENT);
+            ASSERT(bp!=0);
+            ASSERT(bp->flags & status_flags::dynallocated);
+            ASSERT(other.bp!=0);
+            ASSERT(other.bp->flags & status_flags::dynallocated);
+            ++other.bp->refcount;
+            basic * tmpbp=other.bp;
+            if (--bp->refcount==0) {
+                delete bp;
+            }
+            bp=tmpbp;
+            return *this;
+        }
+#else
+;
+#endif // def INLINE_EX_CONSTRUCTORS
+
+    // other constructors
+public:
+    ex(basic const & other)
+#ifdef INLINE_EX_CONSTRUCTORS
+    {
+        debugmsg("ex constructor from basic",LOGLEVEL_CONSTRUCT);
+        construct_from_basic(other);
+    }
+#else
+;
+#endif // def INLINE_EX_CONSTRUCTORS
+    
+    ex(int const i);
+    ex(unsigned int const i);
+    ex(long const i);
+    ex(unsigned long const i);
+    ex(double const d);
+
+    // functions overriding virtual functions from bases classes
+    // none
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+
+    // non-virtual functions in this class
+public:
+    void swap(ex & other);
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent=0) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, const char *var_name) const;
+    void dbgprint(void) const;
+    void dbgprinttree(void) const;
+    bool info(unsigned inf) const;
+    int nops() const;
+    ex expand(unsigned options=0) const;
+    bool has(ex const & other) const;
+    int degree(symbol const & s) const;
+    int ldegree(symbol const & s) const;
+    ex coeff(symbol const & s, int const n=1) const;
+    ex lcoeff(symbol const & s) const { return coeff(s, degree(s)); }
+    ex tcoeff(symbol const & s) const { return coeff(s, ldegree(s)); }
+    ex numer(bool normalize = true) const;
+    ex denom(bool normalize = true) const;
+    ex unit(const symbol &x) const;
+    ex content(const symbol &x) const;
+    numeric integer_content(void) const;
+    ex primpart(const symbol &x) const;
+    ex primpart(const symbol &x, const ex &cont) const;
+    ex normal(int level = 0) const;
+    ex smod(const numeric &xi) const;
+    numeric max_coefficient(void) const;
+    ex collect(symbol const & s) const;
+    ex eval(int level = 0) const;
+    ex evalf(int level = 0) const;
+    ex diff(symbol const & s, unsigned nth = 1) const;
+    ex series(symbol const & s, ex const & point, int order = 6) const;
+    ex subs(lst const & ls, lst const & lr) const;
+    ex subs(ex const & e) const;
+    exvector get_indices(void) const;
+    ex simplify_ncmul(exvector const & v) const;
+    ex operator[](ex const & index) const;
+    ex operator[](int const i) const;
+    ex op(int const i) const;
+    ex & let_op(int const i);
+    int compare(ex const & other) const
+#ifdef INLINE_EX_CONSTRUCTORS
+        {
+            ASSERT(bp!=0);
+            ASSERT(other.bp!=0);
+            if (bp==other.bp) {
+                // special case: both expression point to same basic, trivially equal
+                return 0; 
+            }
+            return bp->compare(*other.bp);
+        }
+#else
+;
+#endif // def INLINE_EX_CONSTRUCTORS
+    bool is_equal(ex const & other) const
+#ifdef INLINE_EX_CONSTRUCTORS
+        {
+            ASSERT(bp!=0);
+            ASSERT(other.bp!=0);
+            if (bp==other.bp) {
+                // special case: both expression point to same basic, trivially equal
+                return true; 
+            }
+            return bp->is_equal(*other.bp);
+        }
+#else
+;
+#endif // def INLINE_EX_CONSTRUCTORS
+    bool is_zero(void) const {return compare(exZERO()) == 0;};
+        
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    unsigned gethash(void) const;
+
+    ex exadd(ex const & rh) const;
+    ex exmul(ex const & rh) const;
+    ex exncmul(ex const & rh) const;
+private:
+    void construct_from_basic(basic const & other);
+    void makewriteable();
+
+// member variables
+
+public:
+    basic *bp;
+
+};
+
+// wrapper functions around member functions
+inline int nops(ex const & thisex)
+{ return thisex.nops(); }
+
+inline ex expand(ex const & thisex, unsigned options = 0)
+{ return thisex.expand(options); }
+
+inline bool has(ex const & thisex, ex const & other)
+{ return thisex.has(other); }
+
+inline int degree(ex const & thisex, symbol const & s)
+{ return thisex.degree(s); }
+
+inline int ldegree(ex const & thisex, symbol const & s)
+{ return thisex.ldegree(s); }
+
+inline ex coeff(ex const & thisex, symbol const & s, int const n=1)
+{ return thisex.coeff(s, n); }
+
+inline ex numer(ex const & thisex, bool normalize = true)
+{ return thisex.numer(normalize); }
+
+inline ex denom(ex const & thisex, bool normalize = true)
+{ return thisex.denom(normalize); }
+
+inline ex normal(ex const & thisex, int level=0)
+{ return thisex.normal(level); }
+
+inline ex collect(ex const & thisex, symbol const & s)
+{ return thisex.collect(s); }
+
+inline ex eval(ex const & thisex, int level = 0)
+{ return thisex.eval(level); }
+
+inline ex evalf(ex const & thisex, int level = 0)
+{ return thisex.evalf(level); }
+
+inline ex diff(ex const & thisex, symbol const & s, unsigned nth = 1)
+{ return thisex.diff(s, nth); }
+
+inline ex subs(ex const & thisex, ex const & e)
+{ return thisex.subs(e); }
+
+inline ex subs(ex const & thisex, lst const & ls, lst const & lr)
+{ return thisex.subs(ls, lr); }
+
+inline void swap(ex & e1, ex & e2)
+{ e1.swap(e2); }
+
+#endif // ndef _EX_H_
diff --git a/ginac/expair.h b/ginac/expair.h
new file mode 100644 (file)
index 0000000..ffe9532
--- /dev/null
@@ -0,0 +1,173 @@
+/** @file expair.h */
+
+/** A pair of expressions.
+ *  This similar to, but slightly extended STL's pair<> but we need to account
+ *  for methods like .compare() */
+class expair
+{
+public:
+    expair() {}
+    ~expair() {}
+    expair(expair const & other) : rest(other.rest), coeff(other.coeff)
+    {
+        ASSERT(is_ex_exactly_of_type(coeff,numeric));
+    }
+    expair const & operator=(expair const & other)
+    {
+        if (this != &other) {
+            rest=other.rest;
+            coeff=other.coeff;
+        }
+        return *this;
+    }
+    expair(ex const & r, ex const & c) : rest(r), coeff(c)
+    {
+        ASSERT(is_ex_exactly_of_type(coeff,numeric));
+    }
+    
+    bool is_numeric_with_coeff_1(void) const
+    {
+        ASSERT(is_ex_exactly_of_type(coeff,numeric));
+        return is_ex_exactly_of_type(rest,numeric) &&
+               (ex_to_numeric(coeff).compare(numONE())==0);
+    }
+
+    bool is_equal(expair const & other) const
+    {
+        return (rest.is_equal(other.rest) && coeff.is_equal(other.coeff));
+    }
+    bool is_less(expair const & other) const 
+    {
+        return (rest.compare(other.rest)<0) ||
+               (!(other.rest.compare(rest)<0) && (coeff.compare(other.coeff)<0));
+    }
+    int compare(expair const & other) const
+    {
+        int cmpval=rest.compare(other.rest);
+        if (cmpval!=0) return cmpval;
+        cmpval=coeff.compare(other.coeff);
+        return cmpval;
+    }
+
+    bool is_less_old2(expair const & other) const 
+    {
+        /*
+        bool this_numeric_with_coeff_1=is_numeric_with_coeff_1();
+        bool other_numeric_with_coeff_1=other.is_numeric_with_coeff_1();
+        if (this_numeric_with_coeff_1) {
+            if (other_numeric_with_coeff_1) {
+                // both have coeff 1: compare rests
+                return rest.compare(other.rest)<0;
+            }
+            // only this has coeff 1: >
+            return false;
+        } else if (other_numeric_with_coeff_1) {
+            // only other has coeff 1: <
+            return true;
+        }
+        return (rest.compare(other.rest)<0) ||
+               (!(other.rest.compare(rest)<0) &&
+                 (coeff.compare(other.coeff)<0));
+        */
+        if (is_ex_exactly_of_type(rest,numeric) &&
+            is_ex_exactly_of_type(other.rest,numeric)) {
+            if (ex_to_numeric(coeff).compare(numONE())==0) {
+                if (ex_to_numeric(other.coeff).compare(numONE())==0) {
+                    // both have coeff 1: compare rests
+                    return rest.compare(other.rest)<0;
+                }
+                // only this has coeff 1: >
+                return false;
+            } else if (ex_to_numeric(other.coeff).compare(numONE())==0) {
+                // only other has coeff 1: <
+                return true;
+            }
+            // neither has coeff 1: usual compare        
+        }
+        return (rest.compare(other.rest)<0) ||
+               (!(other.rest.compare(rest)<0) &&
+                 (coeff.compare(other.coeff)<0));
+    }
+    int compare_old2(expair const & other) const
+    {
+        if (is_ex_exactly_of_type(rest,numeric) &&
+            is_ex_exactly_of_type(other.rest,numeric)) {
+            if (ex_to_numeric(coeff).compare(numONE())==0) {
+                if (ex_to_numeric(other.coeff).compare(numONE())==0) {
+                    // both have coeff 1: compare rests
+                    return rest.compare(other.rest);
+                }
+                // only this has coeff 1: >
+                return 1;
+            } else if (ex_to_numeric(other.coeff).compare(numONE())==0) {
+                // only other has coeff 1: <
+                return -1;
+            }
+            // neither has coeff 1: usual compare        
+        }
+        /*
+        bool this_numeric_with_coeff_1=is_numeric_with_coeff_1();
+        bool other_numeric_with_coeff_1=other.is_numeric_with_coeff_1();
+        if (this_numeric_with_coeff_1) {
+            if (other_numeric_with_coeff_1) {
+                // both have coeff 1: compare rests
+                return rest.compare(other.rest);
+            }
+            // only this has coeff 1: >
+            return 1;
+        } else if (other_numeric_with_coeff_1) {
+            // only other has coeff 1: <
+            return -1;
+            // neither has coeff 1: usual compare        
+        }
+        */
+        int cmpval=rest.compare(other.rest);
+        if (cmpval!=0) return cmpval;
+        return coeff.compare(other.coeff);
+    }
+    bool is_less_old(expair const & other) const 
+    {
+        return (rest.compare(other.rest)<0) ||
+               (!(other.rest.compare(rest)<0) && (coeff.compare(other.coeff)<0));
+    }
+    int compare_old(expair const & other) const
+    {
+        int cmpval=rest.compare(other.rest);
+        if (cmpval!=0) return cmpval;
+        cmpval=coeff.compare(other.coeff);
+        return cmpval;
+    }
+
+    void printraw(ostream & os) const
+    {
+        os << "expair(";
+        rest.printraw(os);
+        os << ",";
+        coeff.printraw(os);
+        os << ")";
+    }
+
+    ex rest;
+    ex coeff;
+};
+
+class expair_is_less
+{
+public:
+    bool operator()(expair const & lh, expair const & rh) const
+    {
+        return lh.is_less(rh);
+    }
+};
+
+class expair_is_less_old
+{
+public:
+    bool operator()(expair const & lh, expair const & rh) const
+    {
+        return lh.is_less_old(rh);
+    }
+};
+
+
+           
diff --git a/ginac/expairseq.cpp b/ginac/expairseq.cpp
new file mode 100644 (file)
index 0000000..9681138
--- /dev/null
@@ -0,0 +1,1604 @@
+/** @file expairseq.cpp */
+
+#include <algorithm>
+#include <string>
+#include <stdexcept>
+
+#include "ginac.h"
+
+#ifdef EXPAIRSEQ_USE_HASHTAB
+#error "!!!!!!!!TODO: expair_needs_further_processing not yet implemented for hashtabs, sorry. A.F."
+#endif // def EXPAIRSEQ_USE_HASHTAB
+
+//////////
+// helper classes
+//////////
+
+class epp_is_less
+{
+public:
+    bool operator()(epp const & lh, epp const & rh) const
+    {
+        return (*lh).is_less(*rh);
+    }
+};
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+expairseq::expairseq(expairseq const & other)
+{
+    debugmsg("expairseq copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+expairseq const & expairseq::operator=(expairseq const & other)
+{
+    debugmsg("expairseq operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void expairseq::copy(expairseq const & other)
+{
+    basic::copy(other);
+    seq=other.seq;
+    overall_coeff=other.overall_coeff;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    // copy hashtab
+    hashtabsize=other.hashtabsize;
+    if (hashtabsize!=0) {
+    hashmask=other.hashmask;
+        hashtab.resize(hashtabsize);
+        epvector::const_iterator osb=other.seq.begin();
+        for (unsigned i=0; i<hashtabsize; ++i) {
+            hashtab[i].clear();
+            for (epplist::const_iterator cit=other.hashtab[i].begin();
+                 cit!=other.hashtab[i].end(); ++cit) {
+                hashtab[i].push_back(seq.begin()+((*cit)-osb));
+            }
+        }
+    } else {
+        hashtab.clear();
+    }
+#endif // def EXPAIRSEQ_USE_HASHTAB
+}
+
+//////////
+// other constructors
+//////////
+
+expairseq::expairseq(ex const & lh, ex const & rh) : basic(TINFO_EXPAIRSEQ)
+{
+    debugmsg("expairseq constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+    construct_from_2_ex(lh,rh);
+    ASSERT(is_canonical());
+}
+
+expairseq::expairseq(exvector const & v) : basic(TINFO_EXPAIRSEQ)
+{
+    debugmsg("expairseq constructor from exvector",LOGLEVEL_CONSTRUCT);
+    construct_from_exvector(v);
+    ASSERT(is_canonical());
+}
+
+/*
+expairseq::expairseq(epvector const & v, bool do_not_canonicalize) :
+    basic(TINFO_EXPAIRSEQ)
+{
+    debugmsg("expairseq constructor from epvector",LOGLEVEL_CONSTRUCT);
+    if (do_not_canonicalize) {
+        seq=v;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+        combine_same_terms(); // to build hashtab
+#endif // def EXPAIRSEQ_USE_HASHTAB
+    } else {
+        construct_from_epvector(v);
+    }
+    ASSERT(is_canonical());
+}
+*/
+
+expairseq::expairseq(epvector const & v, ex const & oc) :
+    basic(TINFO_EXPAIRSEQ), overall_coeff(oc)
+{
+    debugmsg("expairseq constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
+    construct_from_epvector(v);
+    ASSERT(is_canonical());
+}
+
+expairseq::expairseq(epvector * vp, ex const & oc) :
+    basic(TINFO_EXPAIRSEQ), overall_coeff(oc)
+{
+    debugmsg("expairseq constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
+    ASSERT(vp!=0);
+    construct_from_epvector(*vp);
+    delete vp;
+    ASSERT(is_canonical());
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * expairseq::duplicate() const
+{
+    debugmsg("expairseq duplicate",LOGLEVEL_DUPLICATE);
+    return new expairseq(*this);
+}
+
+bool expairseq::info(unsigned inf) const
+{
+    return basic::info(inf);
+}
+
+int expairseq::nops() const
+{
+    if (overall_coeff.is_equal(default_overall_coeff())) {
+        return seq.size();
+    }
+    return seq.size()+1;
+}
+
+ex expairseq::op(int const i) const
+{
+    if (unsigned(i)<seq.size()) {
+        return recombine_pair_to_ex(seq[i]);
+    }
+    ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
+    return overall_coeff;
+}
+
+ex & expairseq::let_op(int const i)
+{
+    throw(std::logic_error("let_op not defined for expairseq and derived classes (add,mul,...)"));
+}
+
+ex expairseq::eval(int level) const
+{
+    if ((level==1)&&(flags & status_flags::evaluated)) {
+        return *this;
+    }
+
+    epvector * vp=evalchildren(level);
+    if (vp==0) {
+        return this->hold();
+    }
+
+    return (new expairseq(vp,overall_coeff))
+               ->setflag(status_flags::dynallocated |
+                         status_flags::evaluated );
+}
+
+ex expairseq::evalf(int level) const
+{
+    return thisexpairseq(evalfchildren(level),overall_coeff);
+}
+
+ex expairseq::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    ex n=thisexpairseq(normalchildren(level),overall_coeff);
+    return n.bp->basic::normal(sym_lst,repl_lst,level);
+}
+
+ex expairseq::subs(lst const & ls, lst const & lr) const
+{
+    epvector * vp=subschildren(ls,lr);
+    if (vp==0) {
+        return *this;
+    }
+    return thisexpairseq(vp,overall_coeff);
+}
+
+// protected
+
+int expairseq::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other, expairseq));
+    expairseq const & o=static_cast<expairseq const &>(const_cast<basic &>(other));
+
+    int cmpval;
+    
+    // compare number of elements
+    if (seq.size() != o.seq.size()) {
+        return (seq.size()<o.seq.size()) ? -1 : 1;
+    }
+
+    // compare overall_coeff
+    cmpval=overall_coeff.compare(o.overall_coeff);
+    if (cmpval!=0) return cmpval;
+
+    //if (seq.size()==0) return 0; // empty expairseq's are equal
+
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    ASSERT(hashtabsize==o.hashtabsize);
+    if (hashtabsize==0) {
+#endif // def EXPAIRSEQ_USE_HASHTAB
+        epvector::const_iterator cit1=seq.begin();
+        epvector::const_iterator cit2=o.seq.begin();
+        epvector::const_iterator last1=seq.end();
+        epvector::const_iterator last2=o.seq.end();
+        
+        for (; (cit1!=last1)&&(cit2!=last2); ++cit1, ++cit2) {
+            cmpval=(*cit1).compare(*cit2);
+            if (cmpval!=0) return cmpval;
+        }
+
+        ASSERT(cit1==last1);
+        ASSERT(cit2==last2);
+        
+        return 0;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    }
+
+    // compare number of elements in each hashtab entry
+    for (unsigned i=0; i<hashtabsize; ++i) {
+        unsigned cursize=hashtab[i].size();
+        if (cursize != o.hashtab[i].size()) {
+            return (cursize < o.hashtab[i].size()) ? -1 : 1;
+        }
+    }
+    
+    // compare individual (sorted) hashtab entries
+    for (unsigned i=0; i<hashtabsize; ++i) {
+        unsigned sz=hashtab[i].size();
+        if (sz>0) {
+            epplist const & eppl1=hashtab[i];
+            epplist const & eppl2=o.hashtab[i];
+            epplist::const_iterator it1=eppl1.begin();
+            epplist::const_iterator it2=eppl2.begin();
+            while (it1!=eppl1.end()) {
+                cmpval=(*(*it1)).compare(*(*it2));
+                if (cmpval!=0) return cmpval;
+                ++it1;
+                ++it2;
+            }
+        }
+    }
+    
+    return 0; // equal
+#endif // def EXPAIRSEQ_USE_HASHTAB
+}
+
+bool expairseq::is_equal_same_type(basic const & other) const
+{
+    expairseq const & o=dynamic_cast<expairseq const &>(const_cast<basic &>(other));
+
+    // compare number of elements
+    if (seq.size() != o.seq.size()) return false;
+
+    // compare overall_coeff
+    if (!overall_coeff.is_equal(o.overall_coeff)) return false;
+
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    // compare number of elements in each hashtab entry
+    if (hashtabsize!=o.hashtabsize) {
+        cout << "this:" << endl;
+        printtree(cout,0);
+        cout << "other:" << endl;
+        other.printtree(cout,0);
+    }
+        
+    ASSERT(hashtabsize==o.hashtabsize);
+    
+    if (hashtabsize==0) {
+#endif // def EXPAIRSEQ_USE_HASHTAB
+        epvector::const_iterator cit1=seq.begin();
+        epvector::const_iterator cit2=o.seq.begin();
+        epvector::const_iterator last1=seq.end();
+        
+        while (cit1!=last1) {
+            if (!(*cit1).is_equal(*cit2)) return false;
+            ++cit1;
+            ++cit2;
+        }
+        
+        return true;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    }
+
+    for (unsigned i=0; i<hashtabsize; ++i) {
+        if (hashtab[i].size() != o.hashtab[i].size()) return false;
+    }
+
+    // compare individual sorted hashtab entries
+    for (unsigned i=0; i<hashtabsize; ++i) {
+        unsigned sz=hashtab[i].size();
+        if (sz>0) {
+            epplist const & eppl1=hashtab[i];
+            epplist const & eppl2=o.hashtab[i];
+            epplist::const_iterator it1=eppl1.begin();
+            epplist::const_iterator it2=eppl2.begin();
+            while (it1!=eppl1.end()) {
+                if (!(*(*it1)).is_equal(*(*it2))) return false;
+                ++it1;
+                ++it2;
+            }
+        }
+    }
+
+    return true;
+#endif // def EXPAIRSEQ_USE_HASHTAB
+}
+
+unsigned expairseq::return_type(void) const
+{
+    return return_types::noncommutative_composite;
+}
+
+unsigned expairseq::calchash(void) const
+{
+    unsigned v=golden_ratio_hash(tinfo());
+    epvector::const_iterator last=seq.end();
+    for (epvector::const_iterator cit=seq.begin(); cit!=last; ++cit) {
+#ifndef EXPAIRSEQ_USE_HASHTAB
+        v=rotate_left_31(v); // rotation would spoil commutativity
+#endif // ndef EXPAIRSEQ_USE_HASHTAB
+        v ^= (*cit).rest.gethash();
+    }
+
+    v ^= overall_coeff.gethash();
+    v=v & 0x7FFFFFFFU;
+    
+    // store calculated hash value only if object is already evaluated
+    if (flags & status_flags::evaluated) {
+        setflag(status_flags::hash_calculated);
+        hashvalue=v;
+    }
+
+    return v;
+}
+
+ex expairseq::expand(unsigned options) const
+{
+    epvector * vp=expandchildren(options);
+    if (vp==0) {
+        return *this;
+    }
+    return thisexpairseq(vp,overall_coeff);
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// protected
+
+ex expairseq::thisexpairseq(epvector const & v,ex const & oc) const
+{
+    return expairseq(v,oc);
+}
+
+ex expairseq::thisexpairseq(epvector * vp, ex const & oc) const
+{
+    return expairseq(vp,oc);
+}
+
+expair expairseq::split_ex_to_pair(ex const & e) const
+{
+    return expair(e,exONE());
+}
+
+expair expairseq::combine_ex_with_coeff_to_pair(ex const & e,
+                                                ex const & c) const
+{
+    ASSERT(is_ex_exactly_of_type(c,numeric));
+
+    return expair(e,c);
+}
+
+expair expairseq::combine_pair_with_coeff_to_pair(expair const & p,
+                                                  ex const & c) const
+{
+    ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
+    ASSERT(is_ex_exactly_of_type(c,numeric));
+    
+    return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
+}
+
+ex expairseq::recombine_pair_to_ex(expair const & p) const
+{
+    return lst(p.rest,p.coeff);
+}
+
+bool expairseq::expair_needs_further_processing(epp it)
+{
+    return false;
+}
+
+ex expairseq::default_overall_coeff(void) const
+{
+    return exZERO();
+}
+
+void expairseq::combine_overall_coeff(ex const & c)
+{
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    ASSERT(is_ex_exactly_of_type(c,numeric));
+    overall_coeff = ex_to_numeric(overall_coeff).add_dyn(ex_to_numeric(c));
+}
+
+void expairseq::combine_overall_coeff(ex const & c1, ex const & c2)
+{
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    ASSERT(is_ex_exactly_of_type(c1,numeric));
+    ASSERT(is_ex_exactly_of_type(c2,numeric));
+    overall_coeff = ex_to_numeric(overall_coeff).
+                        add_dyn(ex_to_numeric(c1).mul(ex_to_numeric(c2)));
+}
+
+bool expairseq::can_make_flat(expair const & p) const
+{
+    return true;
+}
+
+    
+//////////
+// non-virtual functions in this class
+//////////
+
+void expairseq::construct_from_2_ex_via_exvector(ex const & lh, ex const & rh)
+{
+    exvector v;
+    v.reserve(2);
+    v.push_back(lh);
+    v.push_back(rh);
+    construct_from_exvector(v);
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    ASSERT((hashtabsize==0)||(hashtabsize>=minhashtabsize));
+    ASSERT(hashtabsize==calc_hashtabsize(seq.size()));
+#endif // def EXPAIRSEQ_USE_HASHTAB
+}
+
+void expairseq::construct_from_2_ex(ex const & lh, ex const & rh)
+{
+    if (lh.bp->tinfo()==tinfo()) {
+       if (rh.bp->tinfo()==tinfo()) {
+#ifdef EXPAIRSEQ_USE_HASHTAB
+           unsigned totalsize=ex_to_expairseq(lh).seq.size()+
+                              ex_to_expairseq(rh).seq.size();
+           if (calc_hashtabsize(totalsize)!=0) {
+               construct_from_2_ex_via_exvector(lh,rh);
+           } else {
+#endif // def EXPAIRSEQ_USE_HASHTAB
+               construct_from_2_expairseq(ex_to_expairseq(lh),
+                                          ex_to_expairseq(rh));
+#ifdef EXPAIRSEQ_USE_HASHTAB
+           }
+#endif // def EXPAIRSEQ_USE_HASHTAB
+           return;
+       } else {
+#ifdef EXPAIRSEQ_USE_HASHTAB
+           unsigned totalsize=ex_to_expairseq(lh).seq.size()+1;
+           if (calc_hashtabsize(totalsize)!=0) {
+               construct_from_2_ex_via_exvector(lh,rh);
+           } else {
+#endif // def EXPAIRSEQ_USE_HASHTAB
+               construct_from_expairseq_ex(ex_to_expairseq(lh),rh);
+#ifdef EXPAIRSEQ_USE_HASHTAB
+           }
+#endif // def EXPAIRSEQ_USE_HASHTAB
+           return;
+       }
+    } else if (rh.bp->tinfo()==tinfo()) {
+#ifdef EXPAIRSEQ_USE_HASHTAB
+        unsigned totalsize=ex_to_expairseq(rh).seq.size()+1;
+        if (calc_hashtabsize(totalsize)!=0) {
+            construct_from_2_ex_via_exvector(lh,rh);
+        } else {
+#endif // def EXPAIRSEQ_USE_HASHTAB
+            construct_from_expairseq_ex(ex_to_expairseq(rh),lh);
+#ifdef EXPAIRSEQ_USE_HASHTAB
+        }
+#endif // def EXPAIRSEQ_USE_HASHTAB
+        return;
+    }
+
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    if (calc_hashtabsize(2)!=0) {
+        construct_from_2_ex_via_exvector(lh,rh);
+        return;
+    }
+    hashtabsize=0;
+#endif // def EXPAIRSEQ_USE_HASHTAB
+    
+    if (is_ex_exactly_of_type(lh,numeric)) {
+        if (is_ex_exactly_of_type(rh,numeric)) {
+            combine_overall_coeff(lh);
+            combine_overall_coeff(rh);
+        } else {
+            combine_overall_coeff(lh);
+            seq.push_back(split_ex_to_pair(rh));
+        }
+    } else {
+        if (is_ex_exactly_of_type(rh,numeric)) {
+            combine_overall_coeff(rh);
+            seq.push_back(split_ex_to_pair(lh));
+        } else {
+            expair p1=split_ex_to_pair(lh);
+            expair p2=split_ex_to_pair(rh);
+
+            int cmpval=p1.rest.compare(p2.rest);
+            if (cmpval==0) {
+                p1.coeff=ex_to_numeric(p1.coeff).add_dyn(ex_to_numeric(p2.coeff));
+                if (!ex_to_numeric(p1.coeff).is_zero()) {
+                    // no further processing is necessary, since this
+                    // one element will usually be recombined in eval()
+                    seq.push_back(p1);
+                }
+            } else {
+                seq.reserve(2);
+                if (cmpval<0) {
+                    seq.push_back(p1);
+                    seq.push_back(p2);
+                } else {
+                    seq.push_back(p2);
+                    seq.push_back(p1);
+                }
+            }
+        }
+    }
+}
+
+void expairseq::construct_from_2_expairseq(expairseq const & s1,
+                                           expairseq const & s2)
+{
+    combine_overall_coeff(s1.overall_coeff);
+    combine_overall_coeff(s2.overall_coeff);
+
+    epvector::const_iterator first1=s1.seq.begin();
+    epvector::const_iterator last1=s1.seq.end();
+    epvector::const_iterator first2=s2.seq.begin();
+    epvector::const_iterator last2=s2.seq.end();
+
+    seq.reserve(s1.seq.size()+s2.seq.size());
+
+    bool needs_further_processing=false;
+    
+    while (first1!=last1 && first2!=last2) {
+        int cmpval=(*first1).rest.compare((*first2).rest);
+        if (cmpval==0) {
+            // combine terms
+            numeric const & newcoeff=ex_to_numeric((*first1).coeff).
+                                     add(ex_to_numeric((*first2).coeff));
+            if (!newcoeff.is_zero()) {
+                seq.push_back(expair((*first1).rest,newcoeff));
+                if (expair_needs_further_processing(seq.end()-1)) {
+                    needs_further_processing = true;
+                }
+            }
+            ++first1;
+            ++first2;
+        } else if (cmpval<0) {
+            seq.push_back(*first1);
+            ++first1;
+        } else {
+            seq.push_back(*first2);
+            ++first2;
+        }
+    }
+    
+    while (first1!=last1) {
+        seq.push_back(*first1);
+        ++first1;
+    }
+    while (first2!=last2) {
+        seq.push_back(*first2);
+        ++first2;
+    }
+
+    if (needs_further_processing) {
+        epvector v=seq;
+        seq.clear();
+        construct_from_epvector(v);
+    }
+}
+
+void expairseq::construct_from_expairseq_ex(expairseq const & s,
+                                            ex const & e)
+{
+    combine_overall_coeff(s.overall_coeff);
+    if (is_ex_exactly_of_type(e,numeric)) {
+        combine_overall_coeff(e);
+        seq=s.seq;
+        return;
+    }
+
+    epvector::const_iterator first=s.seq.begin();
+    epvector::const_iterator last=s.seq.end();
+    expair p=split_ex_to_pair(e);
+
+    seq.reserve(s.seq.size()+1);
+    bool p_pushed=0;
+
+    bool needs_further_processing=false;
+
+    // merge p into s.seq
+    while (first!=last) {
+        int cmpval=(*first).rest.compare(p.rest);
+        if (cmpval==0) {
+            // combine terms
+            numeric const & newcoeff=ex_to_numeric((*first).coeff).
+                                     add(ex_to_numeric(p.coeff));
+            if (!newcoeff.is_zero()) {
+                seq.push_back(expair((*first).rest,newcoeff));
+                if (expair_needs_further_processing(seq.end()-1)) {
+                    needs_further_processing = true;
+                }
+            }
+            ++first;
+            p_pushed=1;
+            break;
+        } else if (cmpval<0) {
+            seq.push_back(*first);
+            ++first;
+        } else {
+            seq.push_back(p);
+            p_pushed=1;
+            break;
+        }
+    }
+
+    if (p_pushed) {
+        // while loop exited because p was pushed, now push rest of s.seq
+        while (first!=last) {
+            seq.push_back(*first);
+            ++first;
+        }
+    } else {
+        // while loop exited because s.seq was pushed, now push p
+        seq.push_back(p);
+    }
+
+    if (needs_further_processing) {
+        epvector v=seq;
+        seq.clear();
+        construct_from_epvector(v);
+    }
+}
+
+void expairseq::construct_from_exvector(exvector const & v)
+{
+    // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
+    //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
+    //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
+    //                  (same for (+,*) -> (*,^)
+
+    make_flat(v);
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    combine_same_terms();
+#else
+    canonicalize();
+    combine_same_terms_sorted_seq();
+#endif // def EXPAIRSEQ_USE_HASHTAB
+}
+
+void expairseq::construct_from_epvector(epvector const & v)
+{
+    // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
+    //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
+    //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
+    //                  (same for (+,*) -> (*,^)
+
+    make_flat(v);
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    combine_same_terms();
+#else
+    canonicalize();
+    combine_same_terms_sorted_seq();
+#endif // def EXPAIRSEQ_USE_HASHTAB
+}
+
+#include <iostream>
+
+void expairseq::make_flat(exvector const & v)
+{
+    exvector::const_iterator cit, citend = v.end();
+
+    // count number of operands which are of same expairseq derived type
+    // and their cumulative number of operands
+    int nexpairseqs=0;
+    int noperands=0;
+    cit=v.begin();
+    while (cit!=citend) {
+        if (cit->bp->tinfo()==tinfo()) {
+            nexpairseqs++;
+            noperands+=ex_to_expairseq(*cit).seq.size();
+        }
+        ++cit;
+    }
+
+    // reserve seq and coeffseq which will hold all operands
+    seq.reserve(v.size()+noperands-nexpairseqs);
+
+    // copy elements and split off numerical part
+    cit=v.begin();
+    while (cit!=citend) {
+        if (cit->bp->tinfo()==tinfo()) {
+            expairseq const & subseqref=ex_to_expairseq(*cit);
+            combine_overall_coeff(subseqref.overall_coeff);
+            epvector::const_iterator cit_s=subseqref.seq.begin();
+            while (cit_s!=subseqref.seq.end()) {
+                seq.push_back(*cit_s);
+                ++cit_s;
+            }
+        } else {
+            if (is_ex_exactly_of_type(*cit,numeric)) {
+                combine_overall_coeff(*cit);
+            } else {
+                seq.push_back(split_ex_to_pair(*cit));
+            }
+        }
+        ++cit;
+    }
+
+    /*
+    cout << "after make flat" << endl;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).printraw(cout);
+    }
+    cout << endl;
+    cout.flush();
+    */
+}
+
+void expairseq::make_flat(epvector const & v)
+{
+    epvector::const_iterator cit, citend = v.end();
+
+    // count number of operands which are of same expairseq derived type
+    // and their cumulative number of operands
+    int nexpairseqs=0;
+    int noperands=0;
+    cit=v.begin();
+    while (cit!=citend) {
+        if (cit->rest.bp->tinfo()==tinfo()) {
+            nexpairseqs++;
+            noperands+=ex_to_expairseq((*cit).rest).seq.size();
+        }
+        ++cit;
+    }
+
+    // reserve seq and coeffseq which will hold all operands
+    seq.reserve(v.size()+noperands-nexpairseqs);
+
+    // copy elements and split off numerical part
+    cit=v.begin();
+    while (cit!=citend) {
+        if ((cit->rest.bp->tinfo()==tinfo())&&can_make_flat(*cit)) {
+            expairseq const & subseqref=ex_to_expairseq((*cit).rest);
+            combine_overall_coeff(ex_to_numeric(subseqref.overall_coeff),
+                                  ex_to_numeric((*cit).coeff));
+            epvector::const_iterator cit_s=subseqref.seq.begin();
+            while (cit_s!=subseqref.seq.end()) {
+                seq.push_back(expair((*cit_s).rest,
+                              ex_to_numeric((*cit_s).coeff).mul_dyn(ex_to_numeric((*cit).coeff))));
+                //seq.push_back(combine_pair_with_coeff_to_pair(*cit_s,
+                //                                              (*cit).coeff));
+                ++cit_s;
+            }
+        } else {
+            if ((*cit).is_numeric_with_coeff_1()) {
+                combine_overall_coeff((*cit).rest);
+            //if (is_ex_exactly_of_type((*cit).rest,numeric)) {
+            //    combine_overall_coeff(recombine_pair_to_ex(*cit));
+            } else {
+                seq.push_back(*cit);
+            }
+        }
+        ++cit;
+    }
+}
+
+epvector * expairseq::bubblesort(epvector::iterator itbegin, epvector::iterator itend)
+{
+    unsigned n=itend-itbegin;
+
+    epvector * sp=new epvector;
+    sp->reserve(n);
+
+    epvector::iterator last=itend-1;
+    for (epvector::iterator it1=itbegin; it1!=last; ++it1) {
+        for (epvector::iterator it2=it1+1; it2!=itend; ++it2) {
+            if ((*it2).rest.compare((*it1).rest)<0) {
+                iter_swap(it1,it2);
+            }
+        }
+        sp->push_back(*it1);
+    }
+    sp->push_back(*last);
+    return sp;
+}
+
+epvector * expairseq::mergesort(epvector::iterator itbegin, epvector::iterator itend)
+{
+    unsigned n=itend-itbegin;
+    /*
+    if (n==1) {
+        epvector * sp=new epvector;
+        sp->push_back(*itbegin);
+        return sp;
+    }
+    */
+    if (n<16) return bubblesort(itbegin, itend);
+    unsigned m=n/2;
+    
+    epvector * s1p=mergesort(itbegin, itbegin+m);
+    epvector * s2p=mergesort(itbegin+m, itend);
+
+    epvector * sp=new epvector;
+    sp->reserve(s1p->size()+s2p->size());
+
+    epvector::iterator first1=s1p->begin();
+    epvector::iterator last1=s1p->end();
+
+    epvector::iterator first2=s2p->begin();
+    epvector::iterator last2=s2p->end();
+    
+    while (first1 != last1 && first2 != last2) {
+        if ((*first1).rest.compare((*first2).rest)<0) {
+            sp->push_back(*first1);
+            ++first1;
+        } else {
+            sp->push_back(*first2);
+            ++first2;
+        }
+    }
+
+    if (first1 != last1) {
+        while (first1 != last1) {
+            sp->push_back(*first1);
+            ++first1;
+        }
+    } else {
+        while (first2 != last2) {
+            sp->push_back(*first2);
+            ++first2;
+        }
+    }
+
+    delete s1p;
+    delete s2p;
+    
+    return sp;
+}
+            
+
+void expairseq::canonicalize(void)
+{
+    // canonicalize
+    sort(seq.begin(),seq.end(),expair_is_less());
+    /*
+    sort(seq.begin(),seq.end(),expair_is_less_old());
+    if (seq.size()>1) {
+        if (is_ex_exactly_of_type((*(seq.begin())).rest,numeric)) {
+            sort(seq.begin(),seq.end(),expair_is_less());
+        } else {
+            epvector::iterator last_numeric=seq.end();
+            do {
+                last_numeric--;
+            } while (is_ex_exactly_of_type((*last_numeric).rest,numeric));
+            last_numeric++;
+            sort(last_numeric,seq.end(),expair_is_less());
+        }
+    }
+    */
+    
+    /*
+    epvector * sorted_seqp=mergesort(seq.begin(),seq.end());
+    epvector::iterator last=sorted_seqp->end();
+    epvector::iterator it2=seq.begin();
+    for (epvector::iterator it1=sorted_seqp->begin(); it1!=last; ++it1, ++it2) {
+        iter_swap(it1,it2);
+    }
+    delete sorted_seqp;
+    */
+
+    /*
+    cout << "after canonicalize" << endl;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).printraw(cout);
+    }
+    cout << endl;
+    cout.flush();
+    */
+}
+
+void expairseq::combine_same_terms_sorted_seq(void)
+{
+    bool needs_further_processing=false;
+    
+    // combine same terms, drop term with coeff 0
+    if (seq.size()>1) {
+        epvector::iterator itin1=seq.begin();
+        epvector::iterator itin2=itin1+1;
+        epvector::iterator itout=itin1;
+        epvector::iterator last=seq.end();
+        // must_copy will be set to true the first time some combination is possible
+        // from then on the sequence has changed and must be compacted
+        bool must_copy=false;
+        while (itin2!=last) {
+            if ((*itin1).rest.compare((*itin2).rest)==0) {
+                (*itin1).coeff=ex_to_numeric((*itin1).coeff).
+                               add_dyn(ex_to_numeric((*itin2).coeff));
+                if (expair_needs_further_processing(itin1)) {
+                    needs_further_processing = true;
+                }
+                must_copy=true;
+            } else {
+                if (!ex_to_numeric((*itin1).coeff).is_zero()) {
+                    if (must_copy) {
+                        *itout=*itin1;
+                    }
+                    ++itout;
+                }
+                itin1=itin2;
+            }
+            ++itin2;
+        }
+        if (!ex_to_numeric((*itin1).coeff).is_zero()) {
+            if (must_copy) {
+                *itout=*itin1;
+            }
+            ++itout;
+        }
+        if (itout!=last) {
+            seq.erase(itout,last);
+        }
+    }
+
+    /*
+    cout << "after combine" << endl;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).printraw(cout);
+    }
+    cout << endl;
+    cout.flush();
+    */
+    
+    if (needs_further_processing) {
+        epvector v=seq;
+        seq.clear();
+        construct_from_epvector(v);
+    }
+}
+
+#ifdef EXPAIRSEQ_USE_HASHTAB
+
+unsigned expairseq::calc_hashtabsize(unsigned sz) const
+{
+    unsigned size;
+    unsigned nearest_power_of_2 = 1 << log2(sz);
+    //    if (nearest_power_of_2 < maxhashtabsize/hashtabfactor) {
+    //  size=nearest_power_of_2*hashtabfactor;
+    size=nearest_power_of_2/hashtabfactor;
+    if (size<minhashtabsize) return 0;
+    ASSERT(hashtabsize<=0x8000000U); // really max size due to 31 bit hashing
+    // hashtabsize must be a power of 2
+    ASSERT((1U << log2(size))==size);
+    return size;
+}
+
+unsigned expairseq::calc_hashindex(ex const & e) const
+{
+    // calculate hashindex
+    unsigned hash=e.gethash();
+    unsigned hashindex;
+    if (is_a_numeric_hash(hash)) {
+        hashindex=hashmask;
+    } else {
+        hashindex=hash & hashmask;
+        // last hashtab entry is reserved for numerics
+        if (hashindex==hashmask) hashindex=0;
+    }
+    ASSERT(hashindex>=0);
+    ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
+    return hashindex;
+}
+
+void expairseq::shrink_hashtab(void)
+{
+    unsigned new_hashtabsize;
+    while (hashtabsize!=(new_hashtabsize=calc_hashtabsize(seq.size()))) {
+        ASSERT(new_hashtabsize<hashtabsize);
+        if (new_hashtabsize==0) {
+            hashtab.clear();
+            hashtabsize=0;
+            canonicalize();
+            return;
+        }
+        
+        // shrink by a factor of 2
+        unsigned half_hashtabsize=hashtabsize/2;
+        for (unsigned i=0; i<half_hashtabsize-1; ++i) {
+            hashtab[i].merge(hashtab[i+half_hashtabsize],epp_is_less());
+        }
+        // special treatment for numeric hashes
+        hashtab[0].merge(hashtab[half_hashtabsize-1],epp_is_less());
+        hashtab[half_hashtabsize-1]=hashtab[hashtabsize-1];
+        hashtab.resize(half_hashtabsize);
+        hashtabsize=half_hashtabsize;
+        hashmask=hashtabsize-1;
+    }
+}
+
+void expairseq::remove_hashtab_entry(epvector::const_iterator element)
+{
+    if (hashtabsize==0) return; // nothing to do
+    
+    // calculate hashindex of element to be deleted
+    unsigned hashindex=calc_hashindex((*element).rest);
+
+    // find it in hashtab and remove it
+    epplist & eppl=hashtab[hashindex];
+    epplist::iterator epplit=eppl.begin();
+    bool erased=false;
+    while (epplit!=eppl.end()) {
+        if (*epplit == element) {
+            eppl.erase(epplit);
+            erased=true;
+            break;
+        }
+        ++epplit;
+    }
+    if (!erased) {
+        printtree(cout,0);
+        cout << "tried to erase " << element-seq.begin() << endl;
+        cout << "size " << seq.end()-seq.begin() << endl;
+
+        unsigned hashindex=calc_hashindex((*element).rest);
+        epplist & eppl=hashtab[hashindex];
+        epplist::iterator epplit=eppl.begin();
+        bool erased=false;
+        while (epplit!=eppl.end()) {
+            if (*epplit == element) {
+                eppl.erase(epplit);
+                erased=true;
+                break;
+            }
+            ++epplit;
+        }
+        ASSERT(erased);
+    }
+    ASSERT(erased);
+}
+
+void expairseq::move_hashtab_entry(epvector::const_iterator oldpos,
+                                   epvector::iterator newpos)
+{
+    ASSERT(hashtabsize!=0);
+    
+    // calculate hashindex of element which was moved
+    unsigned hashindex=calc_hashindex((*newpos).rest);
+
+    // find it in hashtab and modify it
+    epplist & eppl=hashtab[hashindex];
+    epplist::iterator epplit=eppl.begin();
+    while (epplit!=eppl.end()) {
+        if (*epplit == oldpos) {
+            *epplit=newpos;
+            break;
+        }
+        ++epplit;
+    }
+    ASSERT(epplit!=eppl.end());
+}
+
+void expairseq::sorted_insert(epplist & eppl, epp elem)
+{
+    epplist::iterator current=eppl.begin();
+    while ((current!=eppl.end())&&((*(*current)).is_less(*elem))) {
+        ++current;
+    }
+    eppl.insert(current,elem);
+}    
+
+void expairseq::build_hashtab_and_combine(epvector::iterator & first_numeric,
+                                          epvector::iterator & last_non_zero,
+                                          vector<bool> & touched,
+                                          unsigned & number_of_zeroes)
+{
+    epp current=seq.begin();
+
+    while (current!=first_numeric) {
+        if (is_ex_exactly_of_type((*current).rest,numeric)) {
+            --first_numeric;
+            iter_swap(current,first_numeric);
+        } else {
+            // calculate hashindex
+            unsigned currenthashindex=calc_hashindex((*current).rest);
+
+            // test if there is already a matching expair in the hashtab-list
+            epplist & eppl=hashtab[currenthashindex];
+            epplist::iterator epplit=eppl.begin();
+            while (epplit!=eppl.end()) {
+                if ((*current).rest.is_equal((*(*epplit)).rest)) break;
+                ++epplit;
+            }
+            if (epplit==eppl.end()) {
+                // no matching expair found, append this to end of list
+                sorted_insert(eppl,current);
+                ++current;
+            } else {
+                // epplit points to a matching expair, combine it with current
+                (*(*epplit)).coeff=ex_to_numeric((*(*epplit)).coeff).
+                                   add_dyn(ex_to_numeric((*current).coeff));
+                
+                // move obsolete current expair to end by swapping with last_non_zero element
+                // if this was a numeric, it is swapped with the expair before first_numeric 
+                iter_swap(current,last_non_zero);
+                --first_numeric;
+                if (first_numeric!=last_non_zero) iter_swap(first_numeric,current);
+                --last_non_zero;
+                ++number_of_zeroes;
+                // test if combined term has coeff 0 and can be removed is done later
+                touched[(*epplit)-seq.begin()]=true;
+            }
+        }
+    }
+}    
+
+void expairseq::drop_coeff_0_terms(epvector::iterator & first_numeric,
+                                   epvector::iterator & last_non_zero,
+                                   vector<bool> & touched,
+                                   unsigned & number_of_zeroes)
+{
+    // 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;
+    while (current!=first_numeric) {
+        if (!touched[i]) {
+            ++current;
+            ++i;
+        } else if (!ex_to_numeric((*current).coeff).is_equal(numZERO())) {
+            ++current;
+            ++i;
+        } else {
+            remove_hashtab_entry(current);
+
+            // move element to the end, unless it is already at the end
+            if (current!=last_non_zero) {
+                iter_swap(current,last_non_zero);
+                --first_numeric;
+                bool numeric_swapped=first_numeric!=last_non_zero;
+                if (numeric_swapped) iter_swap(first_numeric,current);
+                epvector::iterator changed_entry;
+
+                if (numeric_swapped) {
+                    changed_entry=first_numeric;
+                } else {
+                    changed_entry=last_non_zero;
+                }
+
+                --last_non_zero;
+                ++number_of_zeroes;
+
+                if (first_numeric!=current) {
+                
+                    // change entry in hashtab which referred to first_numeric or last_non_zero to current
+                    move_hashtab_entry(changed_entry,current);
+                    touched[current-seq.begin()]=touched[changed_entry-seq.begin()];
+                }
+            } else {
+                --first_numeric;
+                --last_non_zero;
+                ++number_of_zeroes;
+            }
+        }
+    }
+    ASSERT(i==current-seq.begin());
+}
+
+bool expairseq::has_coeff_0(void) const
+{
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        if ((*cit).coeff.is_equal(exZERO())) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void expairseq::add_numerics_to_hashtab(epvector::iterator first_numeric,
+                                        epvector::const_iterator last_non_zero)
+{
+    if (first_numeric==seq.end()) return; // no numerics    
+
+    epvector::iterator current=first_numeric;
+    epvector::const_iterator last=last_non_zero+1;
+    while (current!=last) {
+        sorted_insert(hashtab[hashmask],current);
+        ++current;
+    }
+}
+
+void expairseq::combine_same_terms(void)
+{
+    // combine same terms, drop term with coeff 0, move numerics to end
+    
+    // calculate size of hashtab
+    hashtabsize=calc_hashtabsize(seq.size());
+
+    // hashtabsize is a power of 2
+    hashmask=hashtabsize-1;
+
+    // allocate hashtab
+    hashtab.clear();
+    hashtab.resize(hashtabsize);
+
+    if (hashtabsize==0) {
+        canonicalize();
+        combine_same_terms_sorted_seq();
+        ASSERT(!has_coeff_0());
+        return;
+    }
+
+    // iterate through seq, move numerics to end,
+    // fill hashtab and combine same terms
+    epvector::iterator first_numeric=seq.end();
+    epvector::iterator last_non_zero=seq.end()-1;
+
+    vector<bool> touched;
+    touched.reserve(seq.size());
+    for (unsigned i=0; i<seq.size(); ++i) touched[i]=false;
+
+    unsigned number_of_zeroes=0;
+
+    ASSERT(!has_coeff_0());
+    build_hashtab_and_combine(first_numeric,last_non_zero,touched,number_of_zeroes);
+    /*
+    cout << "in combine:" << endl;
+    printtree(cout,0);
+    cout << "size=" << seq.end() - seq.begin() << endl;
+    cout << "first_numeric=" << first_numeric - seq.begin() << endl;
+    cout << "last_non_zero=" << last_non_zero - seq.begin() << endl;
+    for (unsigned i=0; i<seq.size(); ++i) {
+        if (touched[i]) cout << i << " is touched" << endl;
+    }
+    cout << "end in combine" << endl;
+    */
+    
+    // there should not be any terms with coeff 0 from the beginning,
+    // so it should be safe to skip this step
+    if (number_of_zeroes!=0) {
+        drop_coeff_0_terms(first_numeric,last_non_zero,touched,number_of_zeroes);
+        /*
+        cout << "in combine after drop:" << endl;
+        printtree(cout,0);
+        cout << "size=" << seq.end() - seq.begin() << endl;
+        cout << "first_numeric=" << first_numeric - seq.begin() << endl;
+        cout << "last_non_zero=" << last_non_zero - seq.begin() << endl;
+        for (unsigned i=0; i<seq.size(); ++i) {
+            if (touched[i]) cout << i << " is touched" << endl;
+        }
+        cout << "end in combine after drop" << endl;
+        */
+    }
+
+    add_numerics_to_hashtab(first_numeric,last_non_zero);
+
+    // pop zero elements
+    for (unsigned i=0; i<number_of_zeroes; ++i) {
+        seq.pop_back();
+    }
+
+    // shrink hashtabsize to calculated value
+    ASSERT(!has_coeff_0());
+
+    shrink_hashtab();
+
+    ASSERT(!has_coeff_0());
+}
+
+#endif // def EXPAIRSEQ_USE_HASHTAB
+
+bool expairseq::is_canonical() const
+{
+    if (seq.size()<=1) return 1;
+
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    if (hashtabsize>0) return 1; // not canoncalized
+#endif // def EXPAIRSEQ_USE_HASHTAB
+    
+    epvector::const_iterator it=seq.begin();
+    epvector::const_iterator it_last=it;
+    for (++it; it!=seq.end(); 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)) {
+                // 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)) {
+                    printpair(cout,*it_last,0);
+                    cout << ">";
+                    printpair(cout,*it,0);
+                    cout << "\n";
+                    cout << "pair1:" << endl;
+                    (*it_last).rest.printtree(cout);
+                    (*it_last).coeff.printtree(cout);
+                    cout << "pair2:" << endl;
+                    (*it).rest.printtree(cout);
+                    (*it).coeff.printtree(cout);
+                    return 0;
+                }
+            }
+        }
+    }
+    return 1;
+}
+
+epvector * expairseq::expandchildren(unsigned options) const
+{
+    epvector::const_iterator last=seq.end();
+    epvector::const_iterator cit=seq.begin();
+    while (cit!=last) {
+        ex const & expanded_ex=(*cit).rest.expand(options);
+        if (!are_ex_trivially_equal((*cit).rest,expanded_ex)) {
+
+            // something changed, copy seq, eval and return it
+            epvector *s=new epvector;
+            s->reserve(seq.size());
+
+            // copy parts of seq which are known not to have changed
+            epvector::const_iterator cit2=seq.begin();
+            while (cit2!=cit) {
+                s->push_back(*cit2);
+                ++cit2;
+            }
+            // copy first changed element
+            s->push_back(combine_ex_with_coeff_to_pair(expanded_ex,
+                                                       (*cit2).coeff));
+            ++cit2;
+            // copy rest
+            while (cit2!=last) {
+                s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.expand(options),
+                                                           (*cit2).coeff));
+                ++cit2;
+            }
+            return s;
+        }
+        ++cit;
+    }
+    
+    return 0; // nothing has changed
+}
+   
+epvector * expairseq::evalchildren(int level) const
+{
+    // returns a NULL pointer if nothing had to be evaluated
+    // returns a pointer to a newly created epvector otherwise
+    // (which has to be deleted somewhere else)
+
+    if (level==1) {
+        return 0;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+
+    --level;
+    epvector::const_iterator last=seq.end();
+    epvector::const_iterator cit=seq.begin();
+    while (cit!=last) {
+        ex const & evaled_ex=(*cit).rest.eval(level);
+        if (!are_ex_trivially_equal((*cit).rest,evaled_ex)) {
+
+           // something changed, copy seq, eval and return it
+            epvector *s=new epvector;
+            s->reserve(seq.size());
+
+            // copy parts of seq which are known not to have changed
+            epvector::const_iterator cit2=seq.begin();
+            while (cit2!=cit) {
+                s->push_back(*cit2);
+                ++cit2;
+            }
+            // copy first changed element
+            s->push_back(combine_ex_with_coeff_to_pair(evaled_ex,
+                                                       (*cit2).coeff));
+            ++cit2;
+            // copy rest
+            while (cit2!=last) {
+                s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.eval(level),
+                                                           (*cit2).coeff));
+                ++cit2;
+            }
+            return s;
+        }
+        ++cit;
+    }
+    
+    return 0; // nothing has changed
+}
+
+epvector expairseq::evalfchildren(int level) const
+{
+    epvector s;
+    s.reserve(seq.size());
+
+    if (level==1) {
+        return seq;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    --level;
+    for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back(combine_ex_with_coeff_to_pair((*it).rest.evalf(level),
+                                                  (*it).coeff));
+    }
+    return s;
+}
+
+epvector expairseq::normalchildren(int level) const
+{
+    epvector s;
+    s.reserve(seq.size());
+
+    if (level==1) {
+        return seq;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    --level;
+    for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back(combine_ex_with_coeff_to_pair((*it).rest.normal(level),
+                                                  (*it).coeff));
+    }
+    return s;
+}
+
+epvector expairseq::diffchildren(symbol const & y) const
+{
+    epvector s;
+    s.reserve(seq.size());
+
+    for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back(combine_ex_with_coeff_to_pair((*it).rest.diff(y),
+                                                  (*it).coeff));
+    }
+    return s;
+}
+
+epvector * expairseq::subschildren(lst const & ls, lst const & lr) 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)
+
+    epvector::const_iterator last=seq.end();
+    epvector::const_iterator cit=seq.begin();
+    while (cit!=last) {
+        ex const & subsed_ex=(*cit).rest.subs(ls,lr);
+        if (!are_ex_trivially_equal((*cit).rest,subsed_ex)) {
+
+            // something changed, copy seq, subs and return it
+            epvector *s=new epvector;
+            s->reserve(seq.size());
+
+            // copy parts of seq which are known not to have changed
+            epvector::const_iterator cit2=seq.begin();
+            while (cit2!=cit) {
+                s->push_back(*cit2);
+                ++cit2;
+            }
+            // copy first changed element
+            s->push_back(combine_ex_with_coeff_to_pair(subsed_ex,
+                                                       (*cit2).coeff));
+            ++cit2;
+            // copy rest
+            while (cit2!=last) {
+                s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.subs(ls,lr),
+                                                           (*cit2).coeff));
+                ++cit2;
+           }
+            return s;
+        }
+        ++cit;
+    }
+    
+    return 0; // nothing has changed
+}
+
+/*
+epvector expairseq::subschildren(lst const & ls, lst const & lr) const
+{
+    epvector s;
+    s.reserve(seq.size());
+
+    for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back(split_ex_to_pair((*it).rest.subs(ls,lr),(*it).coeff));
+    }
+    return s;
+}
+*/
+
+/*
+void expairseq::sort(epviter first, epviter last, expair_is_less comp)
+{
+    if (first != last) {
+        introsort_loop(first, last, lg(last - first) * 2, comp);
+        __final_insertion_sort(first, last, comp);
+    }
+}
+
+ptrdiff_t expairseq::lg(ptrdiff_t n)
+{
+    ptrdiff_t k;
+    for (k = 0; n > 1; n >>= 1) ++k;
+    return k;
+}
+
+void expairseq::introsort_loop(epviter first, epviter last,
+                               ptrdiff_t depth_limit, expair_is_less comp)
+{
+    while (last - first > stl_threshold) {
+        if (depth_limit == 0) {
+            partial_sort(first, last, last, comp);
+            return;
+        }
+        --depth_limit;
+        epviter cut = unguarded_partition(first, last,
+                      expair(__median(*first, *(first + (last - first)/2),
+                      *(last - 1), comp)), comp);
+        introsort_loop(cut, last, depth_limit, comp);
+        last = cut;
+    }
+}
+
+epviter expairseq::unguarded_partition(epviter first, epviter last, 
+                                       expair pivot, expair_is_less comp)
+{
+    while (1) {
+        while (comp(*first, pivot)) ++first;
+        --last;
+        while (comp(pivot, *last)) --last;
+        if (!(first < last)) return first;
+        iter_swap(first, last);
+        ++first;
+    }
+}
+
+void expairseq::partial_sort(epviter first, epviter middle, epviter last,
+                             expair_is_less comp) {
+  make_heap(first, middle, comp);
+  for (RandomAccessIterator i = middle; i < last; ++i)
+    if (comp(*i, *first))
+      __pop_heap(first, middle, i, T(*i), comp, distance_type(first));
+  sort_heap(first, middle, comp);
+}
+*/
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned expairseq::precedence=10;
+
+#ifdef EXPAIRSEQ_USE_HASHTAB
+unsigned expairseq::maxhashtabsize=0x4000000U;
+unsigned expairseq::minhashtabsize=0x1000U;
+unsigned expairseq::hashtabfactor=1;
+#endif // def EXPAIRSEQ_USE_HASHTAB
+
+//////////
+// global constants
+//////////
+
+const expairseq some_expairseq;
+type_info const & typeid_expairseq=typeid(some_expairseq);
+
diff --git a/ginac/expairseq.h b/ginac/expairseq.h
new file mode 100644 (file)
index 0000000..e6511e8
--- /dev/null
@@ -0,0 +1,183 @@
+/** @file expairseq.h */
+
+#ifndef _EXPAIRSEQ_H_
+#define _EXPAIRSEQ_H_
+
+#include <vector>
+#include <list>
+
+class expairseq;
+
+#include "basic.h"
+#include "ex.h"
+#include "numeric.h"
+#include "debugmsg.h"
+#include "expair.h"
+
+//#define EXPAIRSEQ_USE_HASHTAB
+
+typedef vector<expair> epvector;
+typedef epvector::iterator epviter;
+
+inline void iter_swap(epvector::iterator it1, epvector::iterator it2)
+{
+    debugmsg("iter_swap epvector",LOGLEVEL_NONMEMBER_FUNCTION);
+    (*it1).rest.swap((*it2).rest);
+    (*it1).coeff.swap((*it2).coeff);
+}
+
+typedef epvector::iterator epp;
+typedef list<epp> epplist;
+typedef vector<epplist> epplistvector;
+
+/** A sequence of class expair.
+ *  This is used for time-critical classes like sums and products of terms
+ *  since handling a list of coeff and rest is much faster than handling a
+ *  list of products or powers, respectively. (Incidentally, Maple does it
+ *  the same way.) */
+class expairseq : public basic
+{
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    expairseq() : basic(TINFO_EXPAIRSEQ)
+#ifdef EXPAIRSEQ_USE_HASHTAB
+        , hashtabsize(0)
+#endif // def EXPAIRSEQ_USE_HASHTAB
+        {
+            debugmsg("expairseq default constructor",LOGLEVEL_CONSTRUCT);
+        }
+    ~expairseq()
+        {
+            debugmsg("expairseq destructor",LOGLEVEL_DESTRUCT);
+            destroy(0);
+        }
+    expairseq(expairseq const & other);
+    expairseq const & operator=(expairseq const & other);
+protected:
+    void copy(expairseq const & other);
+    void destroy(bool call_parent)
+        {
+            if (call_parent) basic::destroy(call_parent);
+        };
+
+    // other constructors
+public:
+    expairseq(ex const & lh, ex const & rh);
+    expairseq(exvector const & v);
+    expairseq(epvector const & v, ex const & oc);
+    expairseq(epvector * vp, ex const & oc); // vp will be deleted
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+    int nops() const;
+    ex op(int const i) const;
+    ex & let_op(int const i);
+    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(symbol const & s) const;
+    ex subs(lst const & ls, lst const & lr) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned calchash(void) const;
+    ex expand(unsigned options=0) const;
+
+    // new virtual functions which can be overridden by derived classes
+protected:
+    virtual ex thisexpairseq(epvector const & v, ex const & oc) const;
+    virtual ex thisexpairseq(epvector * vp, ex const & oc) const;
+    virtual void printseq(ostream & os, char delim, unsigned this_precedence,
+                          unsigned upper_precedence) const;
+    virtual void printpair(ostream & os, expair const & p,
+                           unsigned upper_precedence) const;
+    virtual expair split_ex_to_pair(ex const & e) const;
+    virtual expair combine_ex_with_coeff_to_pair(ex const & e,
+                                                 ex const & c) const;
+    virtual expair combine_pair_with_coeff_to_pair(expair const & p,
+                                                   ex const & c) const;
+    virtual ex recombine_pair_to_ex(expair const & p) const;
+    virtual bool expair_needs_further_processing(epp it);
+    virtual ex default_overall_coeff(void) const;
+    virtual void combine_overall_coeff(ex const & c);
+    virtual void combine_overall_coeff(ex const & c1, ex const & c2);
+    virtual bool can_make_flat(expair const & p) const;
+    
+    // non-virtual functions in this class
+protected:
+    void construct_from_2_ex_via_exvector(ex const & lh, ex const & rh);
+    void construct_from_2_ex(ex const & lh, ex const & rh);
+    void construct_from_2_expairseq(expairseq const & s1,
+                                    expairseq const & s2);
+    void construct_from_expairseq_ex(expairseq const & s,
+                                     ex const & e);
+    void construct_from_exvector(exvector const & v);
+    void construct_from_epvector(epvector const & v);
+    void make_flat(exvector const & v);
+    void make_flat(epvector const & v);
+    epvector * bubblesort(epvector::iterator itbegin, epvector::iterator itend);
+    epvector * mergesort(epvector::iterator itbegin, epvector::iterator itend);
+    void canonicalize(void);
+    void combine_same_terms_sorted_seq(void);
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    void combine_same_terms(void);
+    unsigned calc_hashtabsize(unsigned sz) const;
+    unsigned calc_hashindex(ex const & e) const;
+    void shrink_hashtab(void);
+    void remove_hashtab_entry(epvector::const_iterator element);
+    void move_hashtab_entry(epvector::const_iterator oldpos,
+                            epvector::iterator newpos);
+    void sorted_insert(epplist & eppl, epp elem);
+    void build_hashtab_and_combine(epvector::iterator & first_numeric,
+                                   epvector::iterator & last_non_zero,
+                                   vector<bool> & touched,
+                                   unsigned & number_of_zeroes);
+    void drop_coeff_0_terms(epvector::iterator & first_numeric,
+                            epvector::iterator & last_non_zero,
+                            vector<bool> & touched,
+                            unsigned & number_of_zeroes);
+    bool has_coeff_0(void) const;
+    void add_numerics_to_hashtab(epvector::iterator first_numeric,                                              epvector::const_iterator last_non_zero);
+#endif // def EXPAIRSEQ_USE_HASHTAB
+    bool is_canonical() const;
+    epvector * expandchildren(unsigned options) const;
+    epvector * evalchildren(int level) const;
+    epvector evalfchildren(int level) const;
+    epvector normalchildren(int level) const;
+    epvector diffchildren(symbol const & s) const;
+    epvector * subschildren(lst const & ls, lst const & lr) const;
+    
+// member variables
+    
+protected:
+    epvector seq;
+    ex overall_coeff;
+    static unsigned precedence;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    epplistvector hashtab;
+    unsigned hashtabsize;
+    unsigned hashmask;
+    static unsigned maxhashtabsize;
+    static unsigned minhashtabsize;
+    static unsigned hashtabfactor;
+#endif // def EXPAIRSEQ_USE_HASHTAB
+};
+
+// global constants
+
+extern const expairseq some_expairseq;
+extern type_info const & typeid_expairseq;
+
+#define ex_to_expairseq(X) static_cast<expairseq const &>(*(X).bp)
+
+#endif // ndef _EXPAIRSEQ_H_
+
+
diff --git a/ginac/exprseq.cpp b/ginac/exprseq.cpp
new file mode 100644 (file)
index 0000000..9e566c3
--- /dev/null
@@ -0,0 +1,594 @@
+/** @file exprseq.cpp
+ *
+ *  Implementation of GiNaC's exprseq. 
+ *  This file was generated automatically by container.pl.
+ *  Please do not modify it directly, edit the perl script instead!
+ *  container.pl options: $CONTAINER=exprseq
+ *                        $STLHEADER=vector
+ *                        $reserve=1
+ *                        $prepend=0
+ *                        $let_op=0
+ *                        $open_bracket=(
+ *                        $close_bracket=) */
+
+#include <iostream>
+#include <stdexcept>
+
+#include "ginac.h"
+
+#define RESERVE(s,size) (s).reserve(size)
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+exprseq::exprseq() : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq default constructor",LOGLEVEL_CONSTRUCT);
+}
+
+exprseq::~exprseq()
+{
+    debugmsg("exprseq destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+exprseq::exprseq(exprseq const & other)
+{
+    debugmsg("exprseq copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+exprseq const & exprseq::operator=(exprseq const & other)
+{
+    debugmsg("exprseq operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void exprseq::copy(exprseq const & other)
+{
+    basic::copy(other);
+    seq=other.seq;
+}
+
+void exprseq::destroy(bool call_parent)
+{
+    seq.clear();
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+exprseq::exprseq(exvector const & s, bool discardable) :  basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from exvector",
+             LOGLEVEL_CONSTRUCT);
+    if (discardable) {
+        seq.swap(const_cast<exvector &>(s));
+    } else {
+        seq=s;
+    }
+}
+
+exprseq::exprseq(exvector * vp) : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from exvector *",LOGLEVEL_CONSTRUCT);
+    ASSERT(vp!=0);
+    seq.swap(*vp);
+    delete vp;
+}
+
+exprseq::exprseq(ex const & e1) :  basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 1 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,1);
+    seq.push_back(e1);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2) : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 2 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,2);
+    seq.push_back(e1);
+    seq.push_back(e2);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2, ex const & e3)
+    : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 3 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,3);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4) : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 4 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,4);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5) : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 5 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,5);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6)
+    : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 6 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,6);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7) : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 7 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,7);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8) : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 8 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,8);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8, ex const & e9)
+    : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 9 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,9);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+    seq.push_back(e9);
+}
+
+exprseq::exprseq(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8, ex const & e9,
+                     ex const &e10)
+    : basic(TINFO_EXPRSEQ)
+{
+    debugmsg("exprseq constructor from 10 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,10);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+    seq.push_back(e9);
+    seq.push_back(e10);
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * exprseq::duplicate() const
+{
+    debugmsg("exprseq duplicate",LOGLEVEL_DUPLICATE);
+    return new exprseq(*this);
+}
+
+void exprseq::printraw(ostream & os) const
+{
+    debugmsg("exprseq printraw",LOGLEVEL_PRINT);
+
+    os << "exprseq(";
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).bp->printraw(os);
+        os << ",";
+    }
+    os << ")";
+}
+
+void exprseq::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("exprseq print",LOGLEVEL_PRINT);
+    // always print brackets around seq, ignore upper_precedence
+    printseq(os,'(',',',')',precedence,precedence+1);
+}
+
+void exprseq::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("exprseq printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "type=" << typeid(*this).name()
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags
+       << ", nops=" << nops() << endl;
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).printtree(os,indent+delta_indent);
+    }
+    os << string(indent+delta_indent,' ') << "=====" << endl;
+}
+
+// exprseq::info() will be implemented by user elsewhere";
+
+int exprseq::nops() const
+{
+    return seq.size();
+}
+
+// exprseq::let_op() will be implemented by user elsewhere
+
+ex exprseq::expand(unsigned options) const
+{
+    exvector s;
+    RESERVE(s,seq.size());
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).expand(options));
+    }
+
+    return thisexprseq(s);
+}
+
+// a exprseq 'has' an expression if it is this expression itself or a child 'has' it
+
+bool exprseq::has(ex const & other) const
+{
+    ASSERT(other.bp!=0);
+    if (is_equal(*other.bp)) return true;
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        if ((*it).has(other)) return true;
+    }
+    return false;
+}
+
+ex exprseq::eval(int level) const
+{
+    if (level==1) {
+        return this->hold();
+    }
+    return thisexprseq(evalchildren(level));
+}
+
+ex exprseq::evalf(int level) const
+{
+    return thisexprseq(evalfchildren(level));
+}
+
+/** Implementation of ex::normal() for exprseqs. It normalizes the arguments
+ *  and replaces the exprseq by a temporary symbol.
+ *  @see ex::normal */
+ex exprseq::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    ex n=thisexprseq(normalchildren(level));
+    return n.bp->basic::normal(sym_lst,repl_lst,level);
+}
+
+ex exprseq::diff(symbol const & s) const
+{
+    return thisexprseq(diffchildren(s));
+}
+
+ex exprseq::subs(lst const & ls, lst const & lr) const
+{
+    exvector * vp=subschildren(ls,lr);
+    if (vp==0) {
+        return *this;
+    }
+    return thisexprseq(vp);
+}
+
+// protected
+
+int exprseq::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,exprseq));
+    exprseq const & o=static_cast<exprseq const &>
+                                    (const_cast<basic &>(other));
+    int cmpval;
+    exvector::const_iterator it1=seq.begin();
+    exvector::const_iterator it2=o.seq.begin();
+
+    for (; (it1!=seq.end())&&(it2!=o.seq.end()); ++it1, ++it2) {
+        cmpval=(*it1).compare(*it2);
+        if (cmpval!=0) return cmpval;
+    }
+
+    if (it1==seq.end()) {
+        return (it2==o.seq.end() ? 0 : -1);
+    }
+
+    return 1;
+}
+
+bool exprseq::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,exprseq));
+    exprseq const & o=static_cast<exprseq const &>
+                                    (const_cast<basic &>(other));
+    if (seq.size()!=o.seq.size()) return false;
+
+    exvector::const_iterator it1=seq.begin();
+    exvector::const_iterator it2=o.seq.begin();
+
+    for (; it1!=seq.end(); ++it1, ++it2) {
+       if (!(*it1).is_equal(*it2)) return false;
+    }
+
+    return true;
+}
+
+unsigned exprseq::return_type(void) const
+{
+    return return_types::noncommutative_composite;
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// public
+
+exprseq & exprseq::append(ex const & b)
+{
+    ensure_if_modifiable();
+    seq.push_back(b);
+    return *this;
+}
+
+
+
+// protected
+
+void exprseq::printseq(ostream & os, char openbracket, char delim,
+                         char closebracket, unsigned this_precedence,
+                         unsigned upper_precedence) const
+{
+    if (this_precedence<=upper_precedence) os << openbracket;
+    if (seq.size()!=0) {
+        exvector::const_iterator it,it_last;
+        it=seq.begin();
+        it_last=seq.end();
+        --it_last;
+        for (; it!=it_last; ++it) {
+            (*it).bp->print(os,this_precedence);
+            os << delim;
+        }
+        (*it).bp->print(os,this_precedence);
+    }
+    if (this_precedence<=upper_precedence) os << closebracket;
+}
+
+ex exprseq::thisexprseq(exvector const & v) const
+{
+    return exprseq(v);
+}
+
+ex exprseq::thisexprseq(exvector * vp) const
+{
+    return exprseq(vp);
+}
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+
+// none
+
+// protected
+
+bool exprseq::is_canonical() const
+{
+    if (seq.size()<=1) { return 1; }
+
+    exvector::const_iterator it=seq.begin();
+    exvector::const_iterator it_last=it;
+    for (++it; it!=seq.end(); it_last=it, ++it) {
+        if ((*it_last).compare(*it)>0) {
+            if ((*it_last).compare(*it)>0) {
+                cout << *it_last << ">" << *it << "\n";
+                return 0;
+               }
+        }
+    }
+    return 1;
+}
+
+
+exvector exprseq::evalchildren(int level) const
+{
+    exvector s;
+    RESERVE(s,seq.size());
+
+    if (level==1) {
+        return seq;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    --level;
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).eval(level));
+    }
+    return s;
+}
+
+exvector exprseq::evalfchildren(int level) const
+{
+    exvector s;
+    RESERVE(s,seq.size());
+
+    if (level==1) {
+        return seq;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    --level;
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).evalf(level));
+    }
+    return s;
+}
+
+exvector exprseq::normalchildren(int level) const
+{
+    exvector s;
+    RESERVE(s,seq.size());
+
+    if (level==1) {
+        return seq;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    --level;
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).normal(level));
+    }
+    return s;
+}
+
+exvector exprseq::diffchildren(symbol const & y) const
+{
+    exvector s;
+    RESERVE(s,seq.size());
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).diff(y));
+    }
+    return s;
+}
+
+/* obsolete subschildren
+exvector exprseq::subschildren(lst const & ls, lst const & lr) const
+{
+    exvector s;
+    RESERVE(s,seq.size());
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).subs(ls,lr));
+    }
+    return s;
+}
+*/
+
+exvector * exprseq::subschildren(lst const & ls, lst const & lr) 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)
+
+    exvector::const_iterator last=seq.end();
+    exvector::const_iterator cit=seq.begin();
+    while (cit!=last) {
+        ex const & subsed_ex=(*cit).subs(ls,lr);
+        if (!are_ex_trivially_equal(*cit,subsed_ex)) {
+
+            // something changed, copy seq, subs and return it
+            exvector *s=new exvector;
+            RESERVE(*s,seq.size());
+
+            // copy parts of seq which are known not to have changed
+            exvector::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!=last) {
+                s->push_back((*cit2).subs(ls,lr));
+                ++cit2;
+           }
+            return s;
+        }
+        ++cit;
+    }
+    
+    return 0; // nothing has changed
+}
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned exprseq::precedence=10;
+
+//////////
+// global constants
+//////////
+
+const exprseq some_exprseq;
+type_info const & typeid_exprseq=typeid(some_exprseq);
+
diff --git a/ginac/exprseq.h b/ginac/exprseq.h
new file mode 100644 (file)
index 0000000..aeb8a2d
--- /dev/null
@@ -0,0 +1,115 @@
+/** @file exprseq.h
+ *
+ *  Definition of GiNaC's exprseq. 
+ *  This file was generated automatically by container.pl.
+ *  Please do not modify it directly, edit the perl script instead!
+ *  container.pl options: $CONTAINER=exprseq
+ *                        $STLHEADER=vector
+ *                        $reserve=1
+ *                        $prepend=0
+ *                        $let_op=0
+ *                        $open_bracket=(
+ *                        $close_bracket=) */
+
+#ifndef _EXPRSEQ_H_
+#define _EXPRSEQ_H_
+
+#include <vector>
+
+#include <ginac/ginac.h>
+
+typedef vector<ex> exvector;
+
+class exprseq : public basic
+{
+
+public:
+    exprseq();
+    ~exprseq();
+    exprseq(exprseq const & other);
+    exprseq const & operator=(exprseq const & other);
+protected:
+    void copy(exprseq const & other);
+    void destroy(bool call_parent);
+
+public:
+    exprseq(exvector const & s, bool discardable=0);
+    exprseq(exvector * vp); // vp will be deleted
+    explicit exprseq(ex const & e1);
+    explicit exprseq(ex const & e1, ex const & e2);
+    explicit exprseq(ex const & e1, ex const & e2, ex const & e3);
+    explicit exprseq(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4);
+    explicit exprseq(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5);
+    explicit exprseq(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6);
+    explicit exprseq(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7);
+    explicit exprseq(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8);
+    explicit exprseq(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8, ex const & e9);
+    explicit exprseq(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8, ex const & e9,
+             ex const &e10);
+
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printtree(ostream & os, unsigned indent) const;
+    bool info(unsigned inf) const;
+    int nops() const;
+    ex & let_op(int const i);
+    ex expand(unsigned options=0) const;
+    bool has(ex const & 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(symbol const & s) const;
+    ex subs(lst const & ls, lst const & lr) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+
+    // new virtual functions which can be overridden by derived classes
+public:
+    virtual exprseq & append(ex const & b);
+    // no prepend possible for exprseq
+protected:
+    virtual void printseq(ostream & os, char openbracket, char delim,
+                          char closebracket, unsigned this_precedence,
+                          unsigned upper_precedence=0) const;
+    virtual ex thisexprseq(exvector const & v) const;
+    virtual ex thisexprseq(exvector * vp) const;
+
+protected:
+    bool is_canonical() const;
+    exvector evalchildren(int level) const;
+    exvector evalfchildren(int level) const;
+    exvector normalchildren(int level) const;
+    exvector diffchildren(symbol const & s) const;
+    exvector * subschildren(lst const & ls, lst const & lr) const;
+
+protected:
+    exvector seq;
+    static unsigned precedence;
+};
+
+// global constants
+
+extern const exprseq some_exprseq;
+extern type_info const & typeid_exprseq;
+
+// macros
+
+#define ex_to_exprseq(X) (static_cast<exprseq const &>(*(X).bp))
+
+#endif // ndef _EXPRSEQ_H_
+
diff --git a/ginac/exprseq_suppl.cpp b/ginac/exprseq_suppl.cpp
new file mode 100644 (file)
index 0000000..22b35ec
--- /dev/null
@@ -0,0 +1,21 @@
+/** @file exprseq_suppl.cpp
+ *
+ *  Supplement to exprseq.cpp, contains the parts which were
+ *  not automatically generated. */
+
+#include "ginac.h"
+
+bool exprseq::info(unsigned inf) const
+{
+    if (inf==info_flags::exprseq) return 1;
+    return basic::info(inf);
+}
+
+ex & exprseq::let_op(int const i)
+{
+    ASSERT(i>=0);
+    ASSERT(i<nops());
+
+    return seq[i];
+}
+
diff --git a/ginac/fail.cpp b/ginac/fail.cpp
new file mode 100644 (file)
index 0000000..81ad433
--- /dev/null
@@ -0,0 +1,104 @@
+/** @file fail.cpp
+ *
+ *  Implementation of class signaling failure of operation. Considered
+ *  obsolete all this stuff ought to be replaced by exceptions. */
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+fail::fail() : basic(TINFO_FAIL)
+{
+    debugmsg("fail default constructor",LOGLEVEL_CONSTRUCT);
+}
+
+fail::~fail()
+{
+    debugmsg("fail destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+fail::fail(fail const & other)
+{
+    debugmsg("fail copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+fail const & fail::operator=(fail const & other)
+{
+    debugmsg("fail operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void fail::copy(fail const & other)
+{
+    basic::copy(other);
+}
+
+void fail::destroy(bool call_parent)
+{
+    if (call_parent) basic::destroy(call_parent);
+}
+
+
+//////////
+// other constructors
+//////////
+
+// none
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * fail::duplicate() const
+{
+    debugmsg("fail duplicate",LOGLEVEL_DUPLICATE);
+    return new fail(*this);
+}
+
+// protected
+
+int fail::compare_same_type(basic const & other) const
+{
+       // two fails are always identical
+    return 0;
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// none
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const fail some_fail;
+type_info const & typeid_fail=typeid(some_fail);
+
diff --git a/ginac/fail.h b/ginac/fail.h
new file mode 100644 (file)
index 0000000..1ff9948
--- /dev/null
@@ -0,0 +1,58 @@
+/** @file fail.h
+ *
+ *  Interface to class signaling failure of operation. Considered obsolete all
+ *  this stuff ought to be replaced by exceptions. */
+
+#ifndef _FAIL_H_
+#define _FAIL_H_
+
+class fail;
+
+#include "basic.h"
+#include "flags.h"
+
+class fail : public basic
+{
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    fail();
+    ~fail();
+    fail(fail const & other);
+    fail const & operator=(fail const & other);
+protected:
+    void copy(fail const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+    // none
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    unsigned 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
+    // none
+
+// member variables
+// none
+};
+
+// global constants
+
+extern const fail some_fail;
+extern type_info const & typeid_fail;
+
+#endif // ndef _FAIL_H_
+
+
diff --git a/ginac/flags.h b/ginac/flags.h
new file mode 100644 (file)
index 0000000..76fe821
--- /dev/null
@@ -0,0 +1,97 @@
+/** @file flags.h
+ *
+ *  Collection of all flags used through the GiNaC framework. */
+
+#ifndef _FLAGS_H_
+#define _FLAGS_H_
+
+class expand_options {
+public:
+    enum { expand_trigonometric      = 0x0001
+         };
+};
+
+class status_flags {
+public:
+    enum { dynallocated              = 0x0001,
+           evaluated                 = 0x0002,
+           expanded                  = 0x0004,
+           hash_calculated           = 0x0008
+         };
+};
+
+class info_flags {
+public:
+    enum { 
+           // answered by class numeric
+           numeric,
+           real,
+           rational,
+           integer,
+           positive,
+           negative,
+           nonnegative,
+           posint,
+           negint,
+           nonnegint,
+           even,
+           odd,
+           prime,
+
+           // answered by class relation
+           relation,
+           relation_equal,
+           relation_not_equal,
+           relation_less,
+           relation_less_or_equal,
+           relation_greater,
+           relation_greater_or_equal,
+
+           // answered by class symbol
+           symbol,
+
+           // answered by class lst
+           list,
+
+           // answered by class exprseq
+           exprseq,
+
+           // answered by classes numeric, symbol, add, mul, power
+           polynomial,
+           integer_polynomial,
+           rational_polynomial,
+           rational_function,
+
+           // answered by class ex
+           normal_form,
+           
+           // answered by class indexed
+           indexed,      // class can carry indices
+           has_indices,  // object has at least one index
+
+           // answered by class idx
+           idx,
+
+           // answered by class coloridx
+           coloridx,
+
+           // answered by class lorentzidx
+           lorentzidx
+    };
+};
+
+class return_types {
+public:
+    enum { commutative, noncommutative, noncommutative_composite};
+};
+
+class csrc_types {
+public:
+       enum {
+               ctype_float,
+               ctype_double,
+               ctype_cl_N
+       };
+};
+
+#endif // ndef _FLAGS_H_
diff --git a/ginac/function.cpp b/ginac/function.cpp
new file mode 100644 (file)
index 0000000..33bfd5f
--- /dev/null
@@ -0,0 +1,590 @@
+/** @file function.cpp
+ *
+ *  Implementation of class function.
+ *
+ *  This file was generated automatically by function.pl.
+ *  Please do not modify it directly, edit the perl script instead!
+ *  function.pl options: $maxargs=10 */
+
+#include <string>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+function::function() : serial(0)
+{
+    debugmsg("function default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+function::~function()
+{
+    debugmsg("function destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+function::function(function const & other)
+{
+    debugmsg("function copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+function const & function::operator=(function const & other)
+{
+    debugmsg("function operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void function::copy(function const & other)
+{
+    exprseq::copy(other);
+    serial=other.serial;
+}
+
+void function::destroy(bool call_parent)
+{
+    if (call_parent) exprseq::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+function::function(unsigned ser) : serial(ser)
+{
+    debugmsg("function constructor from unsigned",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+// the following lines have been generated for max. 10 parameters
+function::function(unsigned ser, ex const & param1)
+    : exprseq(param1), serial(ser)
+{
+    debugmsg("function constructor from unsigned,1*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2)
+    : exprseq(param1, param2), serial(ser)
+{
+    debugmsg("function constructor from unsigned,2*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2, ex const & param3)
+    : exprseq(param1, param2, param3), serial(ser)
+{
+    debugmsg("function constructor from unsigned,3*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4)
+    : exprseq(param1, param2, param3, param4), serial(ser)
+{
+    debugmsg("function constructor from unsigned,4*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5)
+    : exprseq(param1, param2, param3, param4, param5), serial(ser)
+{
+    debugmsg("function constructor from unsigned,5*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6)
+    : exprseq(param1, param2, param3, param4, param5, param6), serial(ser)
+{
+    debugmsg("function constructor from unsigned,6*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6, ex const & param7)
+    : exprseq(param1, param2, param3, param4, param5, param6, param7), serial(ser)
+{
+    debugmsg("function constructor from unsigned,7*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6, ex const & param7, ex const & param8)
+    : exprseq(param1, param2, param3, param4, param5, param6, param7, param8), serial(ser)
+{
+    debugmsg("function constructor from unsigned,8*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6, ex const & param7, ex const & param8, ex const & param9)
+    : exprseq(param1, param2, param3, param4, param5, param6, param7, param8, param9), serial(ser)
+{
+    debugmsg("function constructor from unsigned,9*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+function::function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6, ex const & param7, ex const & param8, ex const & param9, ex const & param10)
+    : exprseq(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10), serial(ser)
+{
+    debugmsg("function constructor from unsigned,10*ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+// end of generated lines
+
+function::function(unsigned ser, exprseq const & es) : exprseq(es), serial(ser)
+{
+    debugmsg("function constructor from unsigned,exprseq",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+function::function(unsigned ser, exvector const & v, bool discardable) 
+    : exprseq(v,discardable), serial(ser)
+{
+    debugmsg("function constructor from string,exvector,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+function::function(unsigned ser, exvector * vp) 
+    : exprseq(vp), serial(ser)
+{
+    debugmsg("function constructor from unsigned,exvector *",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * function::duplicate() const
+{
+    debugmsg("function duplicate",LOGLEVEL_DUPLICATE);
+    return new function(*this);
+}
+
+void function::printraw(ostream & os) const
+{
+    debugmsg("function printraw",LOGLEVEL_PRINT);
+
+    ASSERT(serial<registered_functions().size());
+
+    os << "function(name=" << registered_functions()[serial].name;
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        os << ",";
+        (*it).bp->print(os);
+    }
+    os << ")";
+}
+
+void function::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("function print",LOGLEVEL_PRINT);
+
+    ASSERT(serial<registered_functions().size());
+
+    os << registered_functions()[serial].name;
+    printseq(os,'(',',',')',exprseq::precedence,function::precedence);
+}
+
+void function::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("function printtree",LOGLEVEL_PRINT);
+
+    ASSERT(serial<registered_functions().size());
+
+    os << string(indent,' ') << "function "
+       << registered_functions()[serial].name
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags
+       << ", nops=" << nops() << endl;
+    for (int i=0; i<nops(); ++i) {
+        seq[i].printtree(os,indent+delta_indent);
+    }
+    os << string(indent+delta_indent,' ') << "=====" << endl;
+}
+
+void function::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("function print csrc",LOGLEVEL_PRINT);
+
+    ASSERT(serial<registered_functions().size());
+
+       // Print function name in lowercase
+    string lname;
+    lname=registered_functions()[serial].name;
+    for (unsigned i=0; i<lname.size(); i++)
+        lname[i] = tolower(lname[i]);
+    os << lname << "(";
+
+       // Print arguments, separated by commas
+    exvector::const_iterator it = seq.begin();
+    exvector::const_iterator itend = seq.end();
+    while (it != itend) {
+        it->bp->printcsrc(os, type, 0);
+        it++;
+        if (it != itend)
+            os << ",";
+    }
+    os << ")";
+}
+
+ex function::expand(unsigned options) const
+{
+    return this->setflag(status_flags::expanded);
+}
+
+ex function::eval(int level) const
+{
+    ASSERT(serial<registered_functions().size());
+
+    exvector eseq=evalchildren(level);    
+
+    if (registered_functions()[serial].e==0) {
+        return function(serial,eseq).hold();
+    }
+    switch (registered_functions()[serial].nparams) {
+        // the following lines have been generated for max. 10 parameters
+    case 1:
+        return ((eval_funcp_1)(registered_functions()[serial].e))(eseq[1-1]);
+        break;
+    case 2:
+        return ((eval_funcp_2)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1]);
+        break;
+    case 3:
+        return ((eval_funcp_3)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1], eseq[3-1]);
+        break;
+    case 4:
+        return ((eval_funcp_4)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1]);
+        break;
+    case 5:
+        return ((eval_funcp_5)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1]);
+        break;
+    case 6:
+        return ((eval_funcp_6)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1]);
+        break;
+    case 7:
+        return ((eval_funcp_7)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1], eseq[7-1]);
+        break;
+    case 8:
+        return ((eval_funcp_8)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1], eseq[7-1], eseq[8-1]);
+        break;
+    case 9:
+        return ((eval_funcp_9)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1], eseq[7-1], eseq[8-1], eseq[9-1]);
+        break;
+    case 10:
+        return ((eval_funcp_10)(registered_functions()[serial].e))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1], eseq[7-1], eseq[8-1], eseq[9-1], eseq[10-1]);
+        break;
+
+        // end of generated lines
+    }
+    throw(std::logic_error("function::eval(): invalid nparams"));
+}
+
+ex function::evalf(int level) const
+{
+    ASSERT(serial<registered_functions().size());
+
+    exvector eseq=evalfchildren(level);
+    
+    if (registered_functions()[serial].ef==0) {
+        return function(serial,eseq).hold();
+    }
+    switch (registered_functions()[serial].nparams) {
+        // the following lines have been generated for max. 10 parameters
+    case 1:
+        return ((evalf_funcp_1)(registered_functions()[serial].ef))(eseq[1-1]);
+        break;
+    case 2:
+        return ((evalf_funcp_2)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1]);
+        break;
+    case 3:
+        return ((evalf_funcp_3)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1], eseq[3-1]);
+        break;
+    case 4:
+        return ((evalf_funcp_4)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1]);
+        break;
+    case 5:
+        return ((evalf_funcp_5)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1]);
+        break;
+    case 6:
+        return ((evalf_funcp_6)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1]);
+        break;
+    case 7:
+        return ((evalf_funcp_7)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1], eseq[7-1]);
+        break;
+    case 8:
+        return ((evalf_funcp_8)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1], eseq[7-1], eseq[8-1]);
+        break;
+    case 9:
+        return ((evalf_funcp_9)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1], eseq[7-1], eseq[8-1], eseq[9-1]);
+        break;
+    case 10:
+        return ((evalf_funcp_10)(registered_functions()[serial].ef))(eseq[1-1], eseq[2-1], eseq[3-1], eseq[4-1], eseq[5-1], eseq[6-1], eseq[7-1], eseq[8-1], eseq[9-1], eseq[10-1]);
+        break;
+
+        // end of generated lines
+    }
+    throw(std::logic_error("function::evalf(): invalid nparams"));
+}
+
+ex function::thisexprseq(exvector const & v) const
+{
+    return function(serial,v);
+}
+
+ex function::thisexprseq(exvector * vp) const
+{
+    return function(serial,vp);
+}
+
+/** Implementation of ex::series for functions.
+ *  @see ex::series */
+ex function::series(symbol const & s, ex const & point, int order) const
+{
+    ASSERT(serial<registered_functions().size());
+
+    if (registered_functions()[serial].s==0) {
+        return basic::series(s, point, order);
+    }
+    switch (registered_functions()[serial].nparams) {
+        // the following lines have been generated for max. 10 parameters
+    case 1:
+        return ((series_funcp_1)(registered_functions()[serial].s))(seq[1-1],s,point,order);
+        break;
+    case 2:
+        return ((series_funcp_2)(registered_functions()[serial].s))(seq[1-1], seq[2-1],s,point,order);
+        break;
+    case 3:
+        return ((series_funcp_3)(registered_functions()[serial].s))(seq[1-1], seq[2-1], seq[3-1],s,point,order);
+        break;
+    case 4:
+        return ((series_funcp_4)(registered_functions()[serial].s))(seq[1-1], seq[2-1], seq[3-1], seq[4-1],s,point,order);
+        break;
+    case 5:
+        return ((series_funcp_5)(registered_functions()[serial].s))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1],s,point,order);
+        break;
+    case 6:
+        return ((series_funcp_6)(registered_functions()[serial].s))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1],s,point,order);
+        break;
+    case 7:
+        return ((series_funcp_7)(registered_functions()[serial].s))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1], seq[7-1],s,point,order);
+        break;
+    case 8:
+        return ((series_funcp_8)(registered_functions()[serial].s))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1], seq[7-1], seq[8-1],s,point,order);
+        break;
+    case 9:
+        return ((series_funcp_9)(registered_functions()[serial].s))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1], seq[7-1], seq[8-1], seq[9-1],s,point,order);
+        break;
+    case 10:
+        return ((series_funcp_10)(registered_functions()[serial].s))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1], seq[7-1], seq[8-1], seq[9-1], seq[10-1],s,point,order);
+        break;
+
+        // end of generated lines
+    }
+    throw(std::logic_error("function::series(): invalid nparams"));
+}
+
+// protected
+
+int function::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other, function));
+    function const & o=static_cast<function &>(const_cast<basic &>(other));
+
+    if (serial!=o.serial) {
+        return serial < o.serial ? -1 : 1;
+    }
+    return exprseq::compare_same_type(o);
+}
+
+bool function::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other, function));
+    function const & o=static_cast<function &>(const_cast<basic &>(other));
+
+    if (serial!=o.serial) return false;
+    return exprseq::is_equal_same_type(o);
+}
+
+unsigned function::return_type(void) const
+{
+    if (seq.size()==0) {
+        return return_types::commutative;
+    }
+    return (*seq.begin()).return_type();
+}
+   
+unsigned function::return_type_tinfo(void) const
+{
+    if (seq.size()==0) {
+        return tinfo_key;
+    }
+    return (*seq.begin()).return_type_tinfo();
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// protected
+
+ex function::pdiff(unsigned diff_param) const // partial differentiation
+{
+    ASSERT(serial<registered_functions().size());
+    
+    if (registered_functions()[serial].d==0) {
+        throw(std::logic_error(string("function::pdiff(") + registered_functions()[serial].name + "): no diff function defined"));
+    }
+    switch (registered_functions()[serial].nparams) {
+        // the following lines have been generated for max. 10 parameters
+    case 1:
+        return ((diff_funcp_1)(registered_functions()[serial].d))(seq[1-1],diff_param);
+        break;
+    case 2:
+        return ((diff_funcp_2)(registered_functions()[serial].d))(seq[1-1], seq[2-1],diff_param);
+        break;
+    case 3:
+        return ((diff_funcp_3)(registered_functions()[serial].d))(seq[1-1], seq[2-1], seq[3-1],diff_param);
+        break;
+    case 4:
+        return ((diff_funcp_4)(registered_functions()[serial].d))(seq[1-1], seq[2-1], seq[3-1], seq[4-1],diff_param);
+        break;
+    case 5:
+        return ((diff_funcp_5)(registered_functions()[serial].d))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1],diff_param);
+        break;
+    case 6:
+        return ((diff_funcp_6)(registered_functions()[serial].d))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1],diff_param);
+        break;
+    case 7:
+        return ((diff_funcp_7)(registered_functions()[serial].d))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1], seq[7-1],diff_param);
+        break;
+    case 8:
+        return ((diff_funcp_8)(registered_functions()[serial].d))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1], seq[7-1], seq[8-1],diff_param);
+        break;
+    case 9:
+        return ((diff_funcp_9)(registered_functions()[serial].d))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1], seq[7-1], seq[8-1], seq[9-1],diff_param);
+        break;
+    case 10:
+        return ((diff_funcp_10)(registered_functions()[serial].d))(seq[1-1], seq[2-1], seq[3-1], seq[4-1], seq[5-1], seq[6-1], seq[7-1], seq[8-1], seq[9-1], seq[10-1],diff_param);
+        break;
+
+        // end of generated lines
+    }        
+    throw(std::logic_error("function::pdiff(): no diff function defined"));
+}
+
+vector<registered_function_info> & function::registered_functions(void)
+{
+    static vector<registered_function_info> * rf=new vector<registered_function_info>;
+    return *rf;
+}
+
+// public
+
+// the following lines have been generated for max. 10 parameters
+unsigned function::register_new(char const * nm, eval_funcp_1 e,
+                                 evalf_funcp_1 ef, diff_funcp_1 d, series_funcp_1 s)
+{
+    registered_function_info rfi={nm,1,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_2 e,
+                                 evalf_funcp_2 ef, diff_funcp_2 d, series_funcp_2 s)
+{
+    registered_function_info rfi={nm,2,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_3 e,
+                                 evalf_funcp_3 ef, diff_funcp_3 d, series_funcp_3 s)
+{
+    registered_function_info rfi={nm,3,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_4 e,
+                                 evalf_funcp_4 ef, diff_funcp_4 d, series_funcp_4 s)
+{
+    registered_function_info rfi={nm,4,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_5 e,
+                                 evalf_funcp_5 ef, diff_funcp_5 d, series_funcp_5 s)
+{
+    registered_function_info rfi={nm,5,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_6 e,
+                                 evalf_funcp_6 ef, diff_funcp_6 d, series_funcp_6 s)
+{
+    registered_function_info rfi={nm,6,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_7 e,
+                                 evalf_funcp_7 ef, diff_funcp_7 d, series_funcp_7 s)
+{
+    registered_function_info rfi={nm,7,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_8 e,
+                                 evalf_funcp_8 ef, diff_funcp_8 d, series_funcp_8 s)
+{
+    registered_function_info rfi={nm,8,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_9 e,
+                                 evalf_funcp_9 ef, diff_funcp_9 d, series_funcp_9 s)
+{
+    registered_function_info rfi={nm,9,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+unsigned function::register_new(char const * nm, eval_funcp_10 e,
+                                 evalf_funcp_10 ef, diff_funcp_10 d, series_funcp_10 s)
+{
+    registered_function_info rfi={nm,10,0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+
+// end of generated lines
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const function some_function;
+type_info const & typeid_function=typeid(some_function);
+
diff --git a/ginac/function.h b/ginac/function.h
new file mode 100644 (file)
index 0000000..312b12d
--- /dev/null
@@ -0,0 +1,276 @@
+/** @file function.h
+ *
+ *  Interface to abstract class function (new function concept).
+ *
+ *  This file was generated automatically by function.pl.
+ *  Please do not modify it directly, edit the perl script instead!
+ *  function.pl options: $maxargs=10 */
+
+#ifndef _FUNCTION_H_
+#define _FUNCTION_H_
+
+#include <string>
+#include <vector>
+#include "config.h"
+
+class function;
+
+#include "exprseq.h"
+
+// the following lines have been generated for max. 10 parameters
+#define DECLARE_FUNCTION_1P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1) { \
+    return function(function_index_##NAME, p1); \
+}
+
+#define DECLARE_FUNCTION_2P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2) { \
+    return function(function_index_##NAME, p1, p2); \
+}
+
+#define DECLARE_FUNCTION_3P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2, ex const & p3) { \
+    return function(function_index_##NAME, p1, p2, p3); \
+}
+
+#define DECLARE_FUNCTION_4P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2, ex const & p3, ex const & p4) { \
+    return function(function_index_##NAME, p1, p2, p3, p4); \
+}
+
+#define DECLARE_FUNCTION_5P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2, ex const & p3, ex const & p4, ex const & p5) { \
+    return function(function_index_##NAME, p1, p2, p3, p4, p5); \
+}
+
+#define DECLARE_FUNCTION_6P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2, ex const & p3, ex const & p4, ex const & p5, ex const & p6) { \
+    return function(function_index_##NAME, p1, p2, p3, p4, p5, p6); \
+}
+
+#define DECLARE_FUNCTION_7P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2, ex const & p3, ex const & p4, ex const & p5, ex const & p6, ex const & p7) { \
+    return function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7); \
+}
+
+#define DECLARE_FUNCTION_8P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2, ex const & p3, ex const & p4, ex const & p5, ex const & p6, ex const & p7, ex const & p8) { \
+    return function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8); \
+}
+
+#define DECLARE_FUNCTION_9P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2, ex const & p3, ex const & p4, ex const & p5, ex const & p6, ex const & p7, ex const & p8, ex const & p9) { \
+    return function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8, p9); \
+}
+
+#define DECLARE_FUNCTION_10P(NAME) \
+extern unsigned function_index_##NAME; \
+inline function NAME(ex const & p1, ex const & p2, ex const & p3, ex const & p4, ex const & p5, ex const & p6, ex const & p7, ex const & p8, ex const & p9, ex const & p10) { \
+    return function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
+}
+
+
+// end of generated lines
+
+#define REGISTER_FUNCTION(NAME,E,EF,D,S) \
+unsigned function_index_##NAME=function::register_new(#NAME,E,EF,D,S);
+
+#define BEGIN_TYPECHECK \
+bool automatic_typecheck=true;
+
+#define TYPECHECK(VAR,TYPE) \
+if (!is_ex_exactly_of_type(VAR,TYPE)) { \
+    automatic_typecheck=false; \
+} else
+
+#define TYPECHECK_INTEGER(VAR) \
+if (!(VAR).info(info_flags::integer)) { \
+    automatic_typecheck=false; \
+} else
+
+#define END_TYPECHECK(RV) \
+{} \
+if (!automatic_typecheck) { \
+    return RV.hold(); \
+}
+
+typedef ex (* eval_funcp)();
+typedef ex (* evalf_funcp)();
+typedef ex (* diff_funcp)();
+typedef ex (* series_funcp)();
+
+// the following lines have been generated for max. 10 parameters
+typedef ex (* eval_funcp_1)(ex const &);
+typedef ex (* eval_funcp_2)(ex const &, ex const &);
+typedef ex (* eval_funcp_3)(ex const &, ex const &, ex const &);
+typedef ex (* eval_funcp_4)(ex const &, ex const &, ex const &, ex const &);
+typedef ex (* eval_funcp_5)(ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* eval_funcp_6)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* eval_funcp_7)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* eval_funcp_8)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* eval_funcp_9)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* eval_funcp_10)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+
+typedef ex (* evalf_funcp_1)(ex const &);
+typedef ex (* evalf_funcp_2)(ex const &, ex const &);
+typedef ex (* evalf_funcp_3)(ex const &, ex const &, ex const &);
+typedef ex (* evalf_funcp_4)(ex const &, ex const &, ex const &, ex const &);
+typedef ex (* evalf_funcp_5)(ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* evalf_funcp_6)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* evalf_funcp_7)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* evalf_funcp_8)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* evalf_funcp_9)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+typedef ex (* evalf_funcp_10)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &);
+
+typedef ex (* diff_funcp_1)(ex const &, unsigned);
+typedef ex (* diff_funcp_2)(ex const &, ex const &, unsigned);
+typedef ex (* diff_funcp_3)(ex const &, ex const &, ex const &, unsigned);
+typedef ex (* diff_funcp_4)(ex const &, ex const &, ex const &, ex const &, unsigned);
+typedef ex (* diff_funcp_5)(ex const &, ex const &, ex const &, ex const &, ex const &, unsigned);
+typedef ex (* diff_funcp_6)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, unsigned);
+typedef ex (* diff_funcp_7)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, unsigned);
+typedef ex (* diff_funcp_8)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, unsigned);
+typedef ex (* diff_funcp_9)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, unsigned);
+typedef ex (* diff_funcp_10)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, unsigned);
+
+typedef ex (* series_funcp_1)(ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_2)(ex const &, ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_3)(ex const &, ex const &, ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_4)(ex const &, ex const &, ex const &, ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_5)(ex const &, ex const &, ex const &, ex const &, ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_6)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_7)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_8)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_9)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, symbol const &, ex const &, int);
+typedef ex (* series_funcp_10)(ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, ex const &, symbol const &, ex const &, int);
+
+// end of generated lines
+
+struct registered_function_info {
+    char const * name;
+    unsigned nparams;
+    unsigned options;
+    eval_funcp e;
+    evalf_funcp ef;
+    diff_funcp d;
+    series_funcp s;
+};
+
+/** The class function is used to implement builtin functions like sin, cos...
+    and user defined functions */
+class function : public exprseq
+{
+    friend void ginsh_get_ginac_functions(void);
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    function();
+    ~function();
+    function(function const & other);
+    function const & operator=(function const & other);
+protected:
+    void copy(function const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    function(unsigned ser);
+    // the following lines have been generated for max. 10 parameters
+    function(unsigned ser, ex const & param1);
+    function(unsigned ser, ex const & param1, ex const & param2);
+    function(unsigned ser, ex const & param1, ex const & param2, ex const & param3);
+    function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4);
+    function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5);
+    function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6);
+    function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6, ex const & param7);
+    function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6, ex const & param7, ex const & param8);
+    function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6, ex const & param7, ex const & param8, ex const & param9);
+    function(unsigned ser, ex const & param1, ex const & param2, ex const & param3, ex const & param4, ex const & param5, ex const & param6, ex const & param7, ex const & param8, ex const & param9, ex const & param10);
+
+    // end of generated lines
+    function(unsigned ser, exprseq const & es);
+    function(unsigned ser, exvector const & v, bool discardable=0);
+    function(unsigned ser, exvector * vp); // vp will be deleted
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const; 
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    ex expand(unsigned options=0) const;
+    ex eval(int level=0) const;
+    ex evalf(int level=0) const;
+    ex diff(symbol const & s) const;
+    ex series(symbol const & s, ex const & point, int order) const;
+    ex thisexprseq(exvector const & v) const;
+    ex thisexprseq(exvector * vp) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+protected:
+    ex pdiff(unsigned diff_param) const; // partial differentiation
+    static vector<registered_function_info> & registered_functions(void);
+public:
+    // the following lines have been generated for max. 10 parameters
+    static unsigned register_new(char const * nm, eval_funcp_1 e,
+                                 evalf_funcp_1 ef=0, diff_funcp_1 d=0, series_funcp_1 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_2 e,
+                                 evalf_funcp_2 ef=0, diff_funcp_2 d=0, series_funcp_2 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_3 e,
+                                 evalf_funcp_3 ef=0, diff_funcp_3 d=0, series_funcp_3 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_4 e,
+                                 evalf_funcp_4 ef=0, diff_funcp_4 d=0, series_funcp_4 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_5 e,
+                                 evalf_funcp_5 ef=0, diff_funcp_5 d=0, series_funcp_5 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_6 e,
+                                 evalf_funcp_6 ef=0, diff_funcp_6 d=0, series_funcp_6 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_7 e,
+                                 evalf_funcp_7 ef=0, diff_funcp_7 d=0, series_funcp_7 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_8 e,
+                                 evalf_funcp_8 ef=0, diff_funcp_8 d=0, series_funcp_8 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_9 e,
+                                 evalf_funcp_9 ef=0, diff_funcp_9 d=0, series_funcp_9 s=0);
+    static unsigned register_new(char const * nm, eval_funcp_10 e,
+                                 evalf_funcp_10 ef=0, diff_funcp_10 d=0, series_funcp_10 s=0);
+
+    // end of generated lines
+    unsigned getserial(void) const {return serial;}
+    
+// member variables
+
+protected:
+    unsigned serial;
+};
+
+// utility macros
+
+#define is_ex_the_function(OBJ, FUNCNAME) \
+    (is_ex_exactly_of_type(OBJ, function) && static_cast<function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
+
+// global constants
+
+extern const function some_function;
+extern type_info const & typeid_function;
+
+#endif // ndef _FUNCTION_H_
+
diff --git a/ginac/function.pl b/ginac/function.pl
new file mode 100755 (executable)
index 0000000..6ebdada
--- /dev/null
@@ -0,0 +1,613 @@
+#!/usr/bin/perl -w
+
+$maxargs=10;
+
+sub generate_seq {
+    my ($seq_template,$n)=@_;
+    my ($res,$N);
+    
+    $res='';
+    for ($N=1; $N<=$n; $N++) {
+        $res .= eval('"' . $seq_template . '"');
+        if ($N!=$n) {
+            $res .= ', ';
+        }
+    }
+    return $res;
+}
+
+sub generate {
+    my ($template,$seq_template1,$seq_template2)=@_;
+    my ($res,$N,$SEQ);
+
+    $res='';
+    for ($N=1; $N<=$maxargs; $N++) {
+        $SEQ1=generate_seq($seq_template1,$N);
+        $SEQ2=generate_seq($seq_template2,$N);
+        $res .= eval('"' . $template . '"');
+        $SEQ1=''; # to avoid main::SEQ1 used only once warning
+        $SEQ2=''; # same as above
+    }
+    return $res;
+}
+
+$declare_function_macro=generate(
+    <<'END_OF_DECLARE_FUNCTION_MACRO','ex const & p${N}','p${N}');
+#define DECLARE_FUNCTION_${N}P(NAME) \\
+extern unsigned function_index_##NAME; \\
+inline function NAME(${SEQ1}) { \\
+    return function(function_index_##NAME, ${SEQ2}); \\
+}
+
+END_OF_DECLARE_FUNCTION_MACRO
+
+$typedef_eval_funcp=generate(
+'typedef ex (* eval_funcp_${N})(${SEQ1});'."\n",
+'ex const &','');
+
+$typedef_evalf_funcp=generate(
+'typedef ex (* evalf_funcp_${N})(${SEQ1});'."\n",
+'ex const &','');
+
+$typedef_diff_funcp=generate(
+'typedef ex (* diff_funcp_${N})(${SEQ1}, unsigned);'."\n",
+'ex const &','');
+
+$typedef_series_funcp=generate(
+'typedef ex (* series_funcp_${N})(${SEQ1}, symbol const &, ex const &, int);'."\n",
+'ex const &','');
+
+$constructors_interface=generate(
+'    function(unsigned ser, ${SEQ1});'."\n",
+'ex const & param${N}','');
+
+$register_new_interface=generate(
+'    static unsigned register_new(char const * nm, eval_funcp_${N} e,'."\n".
+'                                 evalf_funcp_${N} ef=0, diff_funcp_${N} d=0, series_funcp_${N} s=0);'.
+"\n",'','');
+
+$constructors_implementation=generate(
+    <<'END_OF_CONSTRUCTORS_IMPLEMENTATION','ex const & param${N}','param${N}');
+function::function(unsigned ser, ${SEQ1})
+    : exprseq(${SEQ2}), serial(ser)
+{
+    debugmsg(\"function constructor from unsigned,${N}*ex\",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+END_OF_CONSTRUCTORS_IMPLEMENTATION
+
+$eval_switch_statement=generate(
+    <<'END_OF_EVAL_SWITCH_STATEMENT','eseq[${N}-1]','');
+    case ${N}:
+        return ((eval_funcp_${N})(registered_functions()[serial].e))(${SEQ1});
+        break;
+END_OF_EVAL_SWITCH_STATEMENT
+
+$evalf_switch_statement=generate(
+    <<'END_OF_EVALF_SWITCH_STATEMENT','eseq[${N}-1]','');
+    case ${N}:
+        return ((evalf_funcp_${N})(registered_functions()[serial].ef))(${SEQ1});
+        break;
+END_OF_EVALF_SWITCH_STATEMENT
+
+$diff_switch_statement=generate(
+    <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','');
+    case ${N}:
+        return ((diff_funcp_${N})(registered_functions()[serial].d))(${SEQ1},diff_param);
+        break;
+END_OF_DIFF_SWITCH_STATEMENT
+
+$series_switch_statement=generate(
+    <<'END_OF_SERIES_SWITCH_STATEMENT','seq[${N}-1]','');
+    case ${N}:
+        return ((series_funcp_${N})(registered_functions()[serial].s))(${SEQ1},s,point,order);
+        break;
+END_OF_SERIES_SWITCH_STATEMENT
+
+$register_new_implementation=generate(
+    <<'END_OF_REGISTER_NEW_IMPLEMENTATION','','');
+unsigned function::register_new(char const * nm, eval_funcp_${N} e,
+                                 evalf_funcp_${N} ef, diff_funcp_${N} d, series_funcp_${N} s)
+{
+    registered_function_info rfi={nm,${N},0,eval_funcp(e),
+                                  evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+    registered_functions().push_back(rfi);
+    return registered_functions().size()-1;
+}
+END_OF_REGISTER_NEW_IMPLEMENTATION
+
+$interface=<<END_OF_INTERFACE;
+/** \@file function.h
+ *
+ *  Interface to abstract class function (new function concept).
+ *
+ *  This file was generated automatically by function.pl.
+ *  Please do not modify it directly, edit the perl script instead!
+ *  function.pl options: \$maxargs=${maxargs} */
+
+#ifndef _FUNCTION_H_
+#define _FUNCTION_H_
+
+#include <string>
+#include <vector>
+#include "config.h"
+
+class function;
+
+#include "exprseq.h"
+
+// the following lines have been generated for max. ${maxargs} parameters
+$declare_function_macro
+// end of generated lines
+
+#define REGISTER_FUNCTION(NAME,E,EF,D,S) \\
+unsigned function_index_##NAME=function::register_new(#NAME,E,EF,D,S);
+
+#define BEGIN_TYPECHECK \\
+bool automatic_typecheck=true;
+
+#define TYPECHECK(VAR,TYPE) \\
+if (!is_ex_exactly_of_type(VAR,TYPE)) { \\
+    automatic_typecheck=false; \\
+} else
+
+#define TYPECHECK_INTEGER(VAR) \\
+if (!(VAR).info(info_flags::integer)) { \\
+    automatic_typecheck=false; \\
+} else
+
+#define END_TYPECHECK(RV) \\
+{} \\
+if (!automatic_typecheck) { \\
+    return RV.hold(); \\
+}
+
+typedef ex (* eval_funcp)();
+typedef ex (* evalf_funcp)();
+typedef ex (* diff_funcp)();
+typedef ex (* series_funcp)();
+
+// the following lines have been generated for max. ${maxargs} parameters
+$typedef_eval_funcp
+$typedef_evalf_funcp
+$typedef_diff_funcp
+$typedef_series_funcp
+// end of generated lines
+
+struct registered_function_info {
+    char const * name;
+    unsigned nparams;
+    unsigned options;
+    eval_funcp e;
+    evalf_funcp ef;
+    diff_funcp d;
+    series_funcp s;
+};
+
+/** The class function is used to implement builtin functions like sin, cos...
+    and user defined functions */
+class function : public exprseq
+{
+    friend void ginsh_get_ginac_functions(void);
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    function();
+    ~function();
+    function(function const & other);
+    function const & operator=(function const & other);
+protected:
+    void copy(function const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    function(unsigned ser);
+    // the following lines have been generated for max. ${maxargs} parameters
+$constructors_interface
+    // end of generated lines
+    function(unsigned ser, exprseq const & es);
+    function(unsigned ser, exvector const & v, bool discardable=0);
+    function(unsigned ser, exvector * vp); // vp will be deleted
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const; 
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    ex expand(unsigned options=0) const;
+    ex eval(int level=0) const;
+    ex evalf(int level=0) const;
+    ex diff(symbol const & s) const;
+    ex series(symbol const & s, ex const & point, int order) const;
+    ex thisexprseq(exvector const & v) const;
+    ex thisexprseq(exvector * vp) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+protected:
+    ex pdiff(unsigned diff_param) const; // partial differentiation
+    static vector<registered_function_info> & registered_functions(void);
+public:
+    // the following lines have been generated for max. ${maxargs} parameters
+$register_new_interface
+    // end of generated lines
+    unsigned getserial(void) const {return serial;}
+    
+// member variables
+
+protected:
+    unsigned serial;
+};
+
+// utility macros
+
+#define is_ex_the_function(OBJ, FUNCNAME) \\
+    (is_ex_exactly_of_type(OBJ, function) && static_cast<function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
+
+// global constants
+
+extern const function some_function;
+extern type_info const & typeid_function;
+
+#endif // ndef _FUNCTION_H_
+
+END_OF_INTERFACE
+
+$implementation=<<END_OF_IMPLEMENTATION;
+/** \@file function.cpp
+ *
+ *  Implementation of class function.
+ *
+ *  This file was generated automatically by function.pl.
+ *  Please do not modify it directly, edit the perl script instead!
+ *  function.pl options: \$maxargs=${maxargs} */
+
+#include <string>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+function::function() : serial(0)
+{
+    debugmsg("function default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+function::~function()
+{
+    debugmsg("function destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+function::function(function const & other)
+{
+    debugmsg("function copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+function const & function::operator=(function const & other)
+{
+    debugmsg("function operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void function::copy(function const & other)
+{
+    exprseq::copy(other);
+    serial=other.serial;
+}
+
+void function::destroy(bool call_parent)
+{
+    if (call_parent) exprseq::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+function::function(unsigned ser) : serial(ser)
+{
+    debugmsg("function constructor from unsigned",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+// the following lines have been generated for max. ${maxargs} parameters
+$constructors_implementation
+// end of generated lines
+
+function::function(unsigned ser, exprseq const & es) : exprseq(es), serial(ser)
+{
+    debugmsg("function constructor from unsigned,exprseq",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+function::function(unsigned ser, exvector const & v, bool discardable) 
+    : exprseq(v,discardable), serial(ser)
+{
+    debugmsg("function constructor from string,exvector,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+function::function(unsigned ser, exvector * vp) 
+    : exprseq(vp), serial(ser)
+{
+    debugmsg("function constructor from unsigned,exvector *",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_FUNCTION;
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * function::duplicate() const
+{
+    debugmsg("function duplicate",LOGLEVEL_DUPLICATE);
+    return new function(*this);
+}
+
+void function::printraw(ostream & os) const
+{
+    debugmsg("function printraw",LOGLEVEL_PRINT);
+
+    ASSERT(serial<registered_functions().size());
+
+    os << "function(name=" << registered_functions()[serial].name;
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        os << ",";
+        (*it).bp->print(os);
+    }
+    os << ")";
+}
+
+void function::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("function print",LOGLEVEL_PRINT);
+
+    ASSERT(serial<registered_functions().size());
+
+    os << registered_functions()[serial].name;
+    printseq(os,'(',',',')',exprseq::precedence,function::precedence);
+}
+
+void function::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("function printtree",LOGLEVEL_PRINT);
+
+    ASSERT(serial<registered_functions().size());
+
+    os << string(indent,' ') << "function "
+       << registered_functions()[serial].name
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags
+       << ", nops=" << nops() << endl;
+    for (int i=0; i<nops(); ++i) {
+        seq[i].printtree(os,indent+delta_indent);
+    }
+    os << string(indent+delta_indent,' ') << "=====" << endl;
+}
+
+void function::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("function print csrc",LOGLEVEL_PRINT);
+
+    ASSERT(serial<registered_functions().size());
+
+       // Print function name in lowercase
+    string lname;
+    lname=registered_functions()[serial].name;
+    for (unsigned i=0; i<lname.size(); i++)
+        lname[i] = tolower(lname[i]);
+    os << lname << "(";
+
+       // Print arguments, separated by commas
+    exvector::const_iterator it = seq.begin();
+    exvector::const_iterator itend = seq.end();
+    while (it != itend) {
+        it->bp->printcsrc(os, type, 0);
+        it++;
+        if (it != itend)
+            os << ",";
+    }
+    os << ")";
+}
+
+ex function::expand(unsigned options) const
+{
+    return this->setflag(status_flags::expanded);
+}
+
+ex function::eval(int level) const
+{
+    ASSERT(serial<registered_functions().size());
+
+    exvector eseq=evalchildren(level);    
+
+    if (registered_functions()[serial].e==0) {
+        return function(serial,eseq).hold();
+    }
+    switch (registered_functions()[serial].nparams) {
+        // the following lines have been generated for max. ${maxargs} parameters
+${eval_switch_statement}
+        // end of generated lines
+    }
+    throw(std::logic_error("function::eval(): invalid nparams"));
+}
+
+ex function::evalf(int level) const
+{
+    ASSERT(serial<registered_functions().size());
+
+    exvector eseq=evalfchildren(level);
+    
+    if (registered_functions()[serial].ef==0) {
+        return function(serial,eseq).hold();
+    }
+    switch (registered_functions()[serial].nparams) {
+        // the following lines have been generated for max. ${maxargs} parameters
+${evalf_switch_statement}
+        // end of generated lines
+    }
+    throw(std::logic_error("function::evalf(): invalid nparams"));
+}
+
+ex function::thisexprseq(exvector const & v) const
+{
+    return function(serial,v);
+}
+
+ex function::thisexprseq(exvector * vp) const
+{
+    return function(serial,vp);
+}
+
+/** Implementation of ex::series for functions.
+ *  \@see ex::series */
+ex function::series(symbol const & s, ex const & point, int order) const
+{
+    ASSERT(serial<registered_functions().size());
+
+    if (registered_functions()[serial].s==0) {
+        return basic::series(s, point, order);
+    }
+    switch (registered_functions()[serial].nparams) {
+        // the following lines have been generated for max. ${maxargs} parameters
+${series_switch_statement}
+        // end of generated lines
+    }
+    throw(std::logic_error("function::series(): invalid nparams"));
+}
+
+// protected
+
+int function::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other, function));
+    function const & o=static_cast<function &>(const_cast<basic &>(other));
+
+    if (serial!=o.serial) {
+        return serial < o.serial ? -1 : 1;
+    }
+    return exprseq::compare_same_type(o);
+}
+
+bool function::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other, function));
+    function const & o=static_cast<function &>(const_cast<basic &>(other));
+
+    if (serial!=o.serial) return false;
+    return exprseq::is_equal_same_type(o);
+}
+
+unsigned function::return_type(void) const
+{
+    if (seq.size()==0) {
+        return return_types::commutative;
+    }
+    return (*seq.begin()).return_type();
+}
+   
+unsigned function::return_type_tinfo(void) const
+{
+    if (seq.size()==0) {
+        return tinfo_key;
+    }
+    return (*seq.begin()).return_type_tinfo();
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// protected
+
+ex function::pdiff(unsigned diff_param) const // partial differentiation
+{
+    ASSERT(serial<registered_functions().size());
+    
+    if (registered_functions()[serial].d==0) {
+        throw(std::logic_error(string("function::pdiff(") + registered_functions()[serial].name + "): no diff function defined"));
+    }
+    switch (registered_functions()[serial].nparams) {
+        // the following lines have been generated for max. ${maxargs} parameters
+${diff_switch_statement}
+        // end of generated lines
+    }        
+    throw(std::logic_error("function::pdiff(): no diff function defined"));
+}
+
+vector<registered_function_info> & function::registered_functions(void)
+{
+    static vector<registered_function_info> * rf=new vector<registered_function_info>;
+    return *rf;
+}
+
+// public
+
+// the following lines have been generated for max. ${maxargs} parameters
+$register_new_implementation
+// end of generated lines
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const function some_function;
+type_info const & typeid_function=typeid(some_function);
+
+END_OF_IMPLEMENTATION
+
+print "Creating interface file function.h...";
+open OUT,">function.h" or die "cannot open function.h";
+print OUT $interface;
+close OUT;
+print "ok.\n";
+
+print "Creating implementation file function.cpp...";
+open OUT,">function.cpp" or die "cannot open function.cpp";
+print OUT $implementation;
+close OUT;
+print "ok.\n";
+
+print "done.\n";
diff --git a/ginac/ginac.h b/ginac/ginac.h
new file mode 100644 (file)
index 0000000..1892097
--- /dev/null
@@ -0,0 +1,36 @@
+/* ginac.h */
+
+#ifndef __GINAC_H__
+#define __GINAC_H__
+
+#include <ginac/add.h>
+#include <ginac/basic.h>
+#include <ginac/constant.h>
+#include <ginac/ex.h>
+#include <ginac/exprseq.h>
+#include <ginac/fail.h>
+#include <ginac/function.h>
+#include <ginac/idx.h>
+#include <ginac/inifcns.h>
+#include <ginac/lst.h>
+#include <ginac/matrix.h>
+#include <ginac/mul.h>
+#include <ginac/ncmul.h>
+#include <ginac/normal.h>
+#include <ginac/numeric.h>
+#include <ginac/operators.h>
+#include <ginac/power.h>
+#include <ginac/series.h>
+#include <ginac/symbol.h>
+#include <ginac/structure.h>
+
+#ifndef GINAC_BASE_ONLY
+#include <ginac/clifford.h>
+#include <ginac/coloridx.h>
+#include <ginac/color.h>
+#include <ginac/isospin.h>
+#include <ginac/lorentzidx.h>
+#include <ginac/simp_lor.h>
+#endif /* ndef GINAC_BASE_ONLY */
+
+#endif /* ndef __GINAC_H__ */
diff --git a/ginac/idx.cpp b/ginac/idx.cpp
new file mode 100644 (file)
index 0000000..9829b87
--- /dev/null
@@ -0,0 +1,427 @@
+/** @file idx.cpp
+ *
+ *  Implementation of GiNaC's indices. */
+
+#include <stdexcept>
+
+#include "ginac.h"
+#include "utils.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+idx::idx() : basic(TINFO_IDX), symbolic(true), covariant(false)
+{
+    debugmsg("idx default constructor",LOGLEVEL_CONSTRUCT);
+    serial=next_serial++;
+    name="index"+ToString(serial);
+}
+
+idx::~idx() 
+{
+    debugmsg("idx destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+idx::idx(idx const & other)
+{
+    debugmsg("idx copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+idx const & idx::operator=(idx const & other)
+{
+    debugmsg("idx operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void idx::copy(idx const & other)
+{
+    basic::copy(other);
+    serial=other.serial;
+    symbolic=other.symbolic;
+    name=other.name;
+    value=other.value;
+    covariant=other.covariant;
+}
+
+void idx::destroy(bool call_parent)
+{
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+idx::idx(bool cov) : basic(TINFO_IDX), symbolic(true), covariant(cov)
+{
+    debugmsg("idx constructor from bool",LOGLEVEL_CONSTRUCT);
+    serial=next_serial++;
+    name="index"+ToString(serial);
+}
+
+idx::idx(string const & n, bool cov) : basic(TINFO_IDX),  
+    symbolic(true), name(n), covariant(cov)
+{
+    debugmsg("idx constructor from string,bool",LOGLEVEL_CONSTRUCT);
+    serial=next_serial++;
+}
+
+idx::idx(char const * n, bool cov) : basic(TINFO_IDX),  
+    symbolic(true), name(n), covariant(cov)
+{
+    debugmsg("idx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
+    serial=next_serial++;
+}
+
+idx::idx(unsigned const v, bool cov) : basic(TINFO_IDX),
+    symbolic(false), value(v), covariant(cov)
+{
+    debugmsg("idx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
+    serial=0;
+}
+
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * idx::duplicate() const
+{
+    debugmsg("idx duplicate",LOGLEVEL_DUPLICATE);
+    return new idx(*this);
+}
+
+void idx::printraw(ostream & os) const
+{
+    debugmsg("idx printraw",LOGLEVEL_PRINT);
+
+    os << "idx(";
+
+    if (symbolic) {
+        os << "symbolic,name=" << name;
+    } else {
+        os << "non symbolic,value=" << value;
+    }
+
+    if (covariant) {
+        os << ",covariant";
+    } else {
+        os << ",contravariant";
+    }
+
+    os << ",serial=" << serial;
+    os << ",hash=" << hashvalue << ",flags=" << flags;
+    os << ")";
+}
+
+void idx::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("idx printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "idx: ";
+
+    if (symbolic) {
+        os << "symbolic,name=" << name;
+    } else {
+        os << "non symbolic,value=" << value;
+    }
+
+    if (covariant) {
+        os << ",covariant";
+    } else {
+        os << ",contravariant";
+    }
+
+    os << ", serial=" << serial
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void idx::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("idx print",LOGLEVEL_PRINT);
+
+    if (covariant) {
+        os << "_";
+    } else {
+        os << "~";
+    }
+    if (symbolic) {
+        os << name;
+    } else {
+        os << value;
+    }
+}
+
+bool idx::info(unsigned inf) const
+{
+    if (inf==info_flags::idx) return true;
+    return basic::info(inf);
+}
+
+ex idx::subs(lst const & ls, lst const & lr) const
+{
+    ASSERT(ls.nops()==lr.nops());
+#ifdef DOASSERT
+    for (int i=0; i<ls.nops(); i++) {
+        ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
+               is_ex_of_type(ls.op(i),idx));
+    }
+#endif // def DOASSERT
+
+    for (int i=0; i<ls.nops(); i++) {
+        if (is_equal(*(ls.op(i)).bp)) {
+            return lr.op(i);
+        }
+    }
+    return *this;
+}
+
+// protected
+
+int idx::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,idx));
+    idx const & o=static_cast<idx const &>
+                             (const_cast<basic &>(other));
+
+    if (covariant!=o.covariant) {
+        // different co/contravariant
+        return covariant ? -1 : 1;
+    }
+    if ((!symbolic) && (!o.symbolic)) {
+        // non-symbolic, of equal type: compare values
+        if (value==o.value) {
+            return 0;
+        }
+        return value<o.value ? -1 : 1;
+    }
+    if (symbolic && o.symbolic) {
+        // both symbolic: compare serials
+        if (serial==o.serial) {
+            return 0;
+        }
+        return serial<o.serial ? -1 : 1;
+    }
+    // one symbolic, one value: value is sorted first
+    return o.symbolic ? -1 : 1;
+}
+
+bool idx::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,idx));
+    idx const & o=static_cast<idx const &>
+                             (const_cast<basic &>(other));
+
+    if (covariant!=o.covariant) return false;
+    if (symbolic!=o.symbolic) return false;
+    if (symbolic && o.symbolic) return serial==o.serial;
+    return value==o.value;
+}    
+
+unsigned idx::calchash(void) const
+{
+    hashvalue=golden_ratio_hash(golden_ratio_hash(tinfo_key ^ serial));
+    setflag(status_flags::hash_calculated);
+    return hashvalue;
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// public
+
+bool idx::is_co_contra_pair(basic const & other) const
+{
+    // like is_equal_same_type(), but tests for different covariant status
+    ASSERT(is_of_type(other,idx));
+    idx const & o=static_cast<idx const &>
+                             (const_cast<basic &>(other));
+
+    if (covariant==o.covariant) return false;
+    if (symbolic!=o.symbolic) return false;
+    if (symbolic && o.symbolic) return serial==o.serial;
+    return value==o.value;
+}    
+
+bool idx::is_symbolic(void) const
+{
+    return symbolic;
+}
+
+unsigned idx::get_value(void) const
+{
+    return value;
+}
+
+bool idx::is_covariant(void) const
+{
+    return covariant;
+}
+
+ex idx::toggle_covariant(void) const
+{
+    idx * i_copy=static_cast<idx *>(duplicate());
+    i_copy->covariant = !i_copy->covariant;
+    i_copy->clearflag(status_flags::hash_calculated);
+    return i_copy->setflag(status_flags::dynallocated);
+}
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// none
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned idx::next_serial=0;
+
+//////////
+// global constants
+//////////
+
+const idx some_idx;
+type_info const & typeid_idx=typeid(some_idx);
+
+//////////
+// other functions
+//////////
+
+int canonicalize_indices(exvector & iv, bool antisymmetric)
+{
+    if (iv.size()<2) {
+        // nothing do to for 0 or 1 indices
+        return INT_MAX;
+    }
+
+    bool something_changed=false;
+    int sig=1;
+    // simple bubble sort algorithm should be sufficient for the small number of indices needed
+    exvector::const_iterator last_idx=iv.end();
+    exvector::const_iterator next_to_last_idx=iv.end()-1;
+    for (exvector::iterator it1=iv.begin(); it1!=next_to_last_idx; ++it1) {
+        for (exvector::iterator it2=it1+1; it2!=last_idx; ++it2) {
+            int cmpval=(*it1).compare(*it2);
+            if (cmpval==1) {
+                iter_swap(it1,it2);
+                something_changed=true;
+                if (antisymmetric) sig=-sig;
+            } else if ((cmpval==0) && antisymmetric) {
+                something_changed=true;
+                sig=0;
+            }
+        }
+    }
+    return something_changed ? sig : INT_MAX;
+}
+
+exvector idx_intersect(exvector const & iv1, exvector const & iv2)
+{
+    // build a vector of symbolic indices contained in iv1 and iv2 simultaneously
+    // assumes (but does not test) that each index occurs at most twice
+    exvector iv_intersect;
+    for (exvector::const_iterator cit1=iv1.begin(); cit1!=iv1.end(); ++cit1) {
+        ASSERT(is_ex_of_type(*cit1,idx));
+        if (ex_to_idx(*cit1).is_symbolic()) {
+            for (exvector::const_iterator cit2=iv2.begin(); cit2!=iv2.end(); ++cit2) {
+                ASSERT(is_ex_of_type(*cit2,idx));
+                if ((*cit1).is_equal(*cit2)) {
+                    iv_intersect.push_back(*cit1);
+                    break;
+                }
+            }
+        }
+    }
+    return iv_intersect;
+}
+
+#define TEST_PERMUTATION(A,B,C,P) \
+    if ((iv3[B].is_equal(iv2[0]))&&(iv3[C].is_equal(iv2[1]))) { \
+        if (antisymmetric) *sig=P; \
+        return iv3[A]; \
+    }
+
+ex permute_free_index_to_front(exvector const & iv3, exvector const & iv2,
+                               bool antisymmetric, int * sig)
+{
+    // match (return value,iv2) to iv3 by permuting indices
+    // iv3 is always cyclic
+
+    ASSERT(iv3.size()==3);
+    ASSERT(iv2.size()==2);
+
+    *sig=1;
+    
+    TEST_PERMUTATION(0,1,2,  1);
+    TEST_PERMUTATION(0,2,1, -1);
+    TEST_PERMUTATION(1,0,2, -1);
+    TEST_PERMUTATION(1,2,0,  1);
+    TEST_PERMUTATION(2,0,1,  1);
+    TEST_PERMUTATION(2,1,0, -1);
+    throw(std::logic_error("permute_free_index_to_front(): no valid permutation found"));
+}
+    
+unsigned subs_index_in_exvector(exvector & v, ex const & is, ex const & ir)
+{
+    exvector::iterator it;
+    unsigned replacements=0;
+    unsigned current_replacements;
+
+    ASSERT(is_ex_of_type(is,idx));
+    ASSERT(is_ex_of_type(ir,idx));
+   
+    for (it=v.begin(); it!=v.end(); ++it) {
+        current_replacements=count_index(*it,is);
+        if (current_replacements>0) {
+            (*it)=(*it).subs(is==ir);
+        }
+        replacements += current_replacements;
+    }
+    return replacements;
+}
+
+unsigned count_index(ex const & e, ex const & i)
+{
+    exvector idxv=e.get_indices();
+    unsigned count=0;
+    for (exvector::const_iterator cit=idxv.begin(); cit!=idxv.end(); ++cit) {
+        if ((*cit).is_equal(i)) count++;
+    }
+    return count;
+}
+
+ex subs_indices(ex const & e, exvector const & idxv_subs,
+                exvector const & idxv_repl)
+{
+    ASSERT(idxv_subs.size()==idxv_repl.size());
+    ex res=e;
+    for (unsigned i=0; i<idxv_subs.size(); ++i) {
+        res=res.subs(idxv_subs[i]==idxv_repl[i]);
+    }
+    return res;
+}
+
+
+
+
diff --git a/ginac/idx.h b/ginac/idx.h
new file mode 100644 (file)
index 0000000..8e460d4
--- /dev/null
@@ -0,0 +1,90 @@
+/** @file idx.h
+ *
+ *  Interface to GiNaC's indices. */
+
+#ifndef _IDX_H_
+#define _IDX_H_
+
+#include <string>
+#include <vector>
+
+#include "basic.h"
+
+class idx : public basic
+{
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    idx();
+    ~idx();
+    idx (idx const & other);
+    idx const & operator=(idx const & other);
+protected:
+    void copy(idx const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    explicit idx(bool cov);
+    explicit idx(string const & n, bool cov=false);
+    explicit idx(char const * n, bool cov=false);
+    explicit idx(unsigned const v, bool cov=false); 
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned calchash(void) const;
+    ex subs(lst const & ls, lst const & lr) const;
+
+    // new virtual functions which can be overridden by derived classes
+public:
+    virtual bool is_co_contra_pair(basic const & other) const;
+    virtual ex toggle_covariant(void) const;
+
+    // non-virtual functions in this class
+public:
+    bool is_symbolic(void) const;
+    unsigned get_value(void) const;
+    bool is_covariant(void) const;
+
+    // member variables
+protected:
+    unsigned serial;
+    bool symbolic;
+    string name;
+    unsigned value;
+    static unsigned next_serial;
+    bool covariant; // x_mu, default is contravariant: x^mu
+};
+
+// global constants
+
+extern const idx some_idx;
+extern type_info const & typeid_idx;
+
+// macros
+
+#define ex_to_idx(X) (static_cast<idx const &>(*(X).bp))
+
+// other functions
+
+typedef vector<ex> exvector;
+
+int canonicalize_indices(exvector & iv, bool antisymmetric=false);
+exvector idx_intersect(exvector const & iv1, exvector const & iv2);
+ex permute_free_index_to_front(exvector const & iv3, exvector const & iv2,
+                               bool antisymmetric, int * sig);
+unsigned subs_index_in_exvector(exvector & v, ex const & is, ex const & ir);
+ex subs_indices(ex const & e, exvector const & idxv_contra,
+                exvector const & idxv_co);
+unsigned count_index(ex const & e, ex const & i);
+
+#endif // ndef _IDX_H_
diff --git a/ginac/indexed.cpp b/ginac/indexed.cpp
new file mode 100644 (file)
index 0000000..2d6419d
--- /dev/null
@@ -0,0 +1,271 @@
+/** @file indexed.cpp
+ *
+ *  Implementation of GiNaC's index carrying objects. */
+
+#include <string>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+indexed::indexed()
+{
+    debugmsg("indexed default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_INDEXED;
+}
+
+indexed::~indexed()
+{
+    debugmsg("indexed destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+indexed::indexed(indexed const & other)
+{
+    debugmsg("indexed copy constructor",LOGLEVEL_CONSTRUCT);
+    copy (other);
+}
+
+indexed const & indexed::operator=(indexed const & other)
+{
+    debugmsg("indexed operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void indexed::copy(indexed const & other)
+{
+    exprseq::copy(other);
+}
+
+void indexed::destroy(bool call_parent)
+{
+    if (call_parent) {
+        exprseq::destroy(call_parent);
+    }
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+indexed::indexed(ex const & i1) : exprseq(i1)
+{
+    debugmsg("indexed constructor from ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_INDEXED;
+    ASSERT(all_of_type_idx());
+}
+
+indexed::indexed(ex const & i1, ex const & i2) : exprseq(i1,i2)
+{
+    debugmsg("indexed constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_INDEXED;
+    ASSERT(all_of_type_idx());
+}
+
+indexed::indexed(ex const & i1, ex const & i2, ex const & i3)
+    : exprseq(i1,i2,i3)
+{
+    debugmsg("indexed constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_INDEXED;
+    ASSERT(all_of_type_idx());
+}
+
+indexed::indexed(exvector const & iv) : exprseq(iv)
+{
+    debugmsg("indexed constructor from exvector",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_INDEXED;
+    ASSERT(all_of_type_idx());
+}
+
+indexed::indexed(exvector * ivp) : exprseq(ivp)
+{
+    debugmsg("indexed constructor from exvector *",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_INDEXED;
+    ASSERT(all_of_type_idx());
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * indexed::duplicate() const
+{
+    debugmsg("indexed duplicate",LOGLEVEL_DUPLICATE);
+    return new indexed(*this);
+}
+
+void indexed::printraw(ostream & os) const
+{
+    debugmsg("indexed printraw",LOGLEVEL_PRINT);
+    os << "indexed(indices=";
+    printrawindices(os);
+    os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+}
+
+void indexed::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("indexed printtree",LOGLEVEL_PRINT);
+    os << string(indent,' ') << "indexed: " << seq.size() << " indices";
+    os << ",hash=" << hashvalue << ",flags=" << flags << endl;
+    printtreeindices(os,indent);
+}
+
+void indexed::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("indexed print",LOGLEVEL_PRINT);
+    os << "UNNAMEDINDEX";
+    printindices(os);
+}
+
+void indexed::printcsrc(ostream & os, unsigned type,
+                        unsigned upper_precedence) const
+{
+    debugmsg("indexed print csrc",LOGLEVEL_PRINT);
+    print(os,upper_precedence);
+}
+
+bool indexed::info(unsigned inf) const
+{
+    if (inf==info_flags::indexed) return true;
+    if (inf==info_flags::has_indices) return seq.size()!=0;
+    return exprseq::info(inf);
+}
+
+exvector indexed::get_indices(void) const
+{
+    return seq;
+
+    /*
+    idxvector filtered_indices;
+    filtered_indices.reserve(indices.size());
+    for (idxvector::const_iterator cit=indices.begin(); cit!=indices.end(); ++cit) {
+        if ((*cit).get_type()==t) {
+            filtered_indices.push_back(*cit);
+        }
+    }
+    return filtered_indices;
+    */
+}
+
+// protected
+
+int indexed::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,indexed));
+    return exprseq::compare_same_type(other);
+}
+
+bool indexed::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,indexed));
+    return exprseq::is_equal_same_type(other);
+}
+
+unsigned indexed::return_type(void) const
+{
+    return return_types::noncommutative;
+}
+   
+unsigned indexed::return_type_tinfo(void) const
+{
+    return tinfo_key;
+}
+
+ex indexed::thisexprseq(exvector const & v) const
+{
+    return indexed(v);
+}
+
+ex indexed::thisexprseq(exvector * vp) const
+{
+    return indexed(vp);
+}
+
+//////////
+// virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// protected
+
+void indexed::printrawindices(ostream & os) const
+{
+    if (seq.size()!=0) {
+        for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+            (*cit).printraw(os);
+            os << ",";
+        }
+    }
+}
+
+void indexed::printtreeindices(ostream & os, unsigned indent) const
+{
+    if (seq.size()!=0) {
+        for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+            os << string(indent+delta_indent,' ');
+            (*cit).printraw(os);
+            os << endl;
+        }
+    }
+}
+
+void indexed::printindices(ostream & os) const
+{
+    if (seq.size()!=0) {
+        if (seq.size()>1) {
+            os << "{";
+        }
+        exvector::const_iterator last=seq.end()-1;
+        exvector::const_iterator cit=seq.begin();
+        for (; cit!=last; ++cit) {
+            (*cit).print(os);
+            os << ",";
+        }
+        (*cit).print(os);
+        if (seq.size()>1) {
+            os << "}";
+        }
+    }
+}
+
+bool indexed::all_of_type_idx(void) const
+{
+    // used only inside of ASSERTs
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        if (!is_ex_of_type(*cit,idx)) return false;
+    }
+    return true;
+}
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const indexed some_indexed;
+type_info const & typeid_indexed=typeid(some_indexed);
+
diff --git a/ginac/indexed.h b/ginac/indexed.h
new file mode 100644 (file)
index 0000000..4bade0b
--- /dev/null
@@ -0,0 +1,81 @@
+/** @file indexed.h
+ *
+ *  Interface to GiNaC's index carrying objects. */
+
+#ifndef _INDEXED_H_
+#define _INDEXED_H_
+
+#include <string>
+
+class indexed;
+
+#include "exprseq.h"
+#include "idx.h"
+
+/** Base class for non-commutative indexed objects */
+class indexed : public exprseq
+{
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    indexed();
+    ~indexed();
+    indexed(indexed const & other);
+    indexed const & operator=(indexed const & other);
+protected:
+    void copy(indexed const & other); 
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    indexed(ex const & i1);
+    indexed(ex const & i1, ex const & i2);
+    indexed(ex const & i1, ex const & i2, ex const & i3);
+    indexed(exvector const & iv);
+    indexed(exvector * iv);
+
+    // functions overriding virtual functions from base classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const;
+    bool info(unsigned inf) const;
+    ex diff(symbol const & s) const;
+    exvector get_indices(void) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    ex thisexprseq(exvector const & v) const;
+    ex thisexprseq(exvector * vp) const;
+
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+protected:
+    void printrawindices(ostream & os) const;
+    void printtreeindices(ostream & os, unsigned indent) const;
+    void printindices(ostream & os) const;
+    bool all_of_type_idx(void) const;
+
+// member variables
+    // none
+};
+
+// global constants
+
+extern const indexed some_indexed;
+extern type_info const & typeid_indexed;
+
+// macros
+
+#define ex_to_indexed(X) static_cast<indexed const &>(*(X).bp)
+
+#endif // ndef _INDEXED_H_
+
+
diff --git a/ginac/inifcns.cpp b/ginac/inifcns.cpp
new file mode 100644 (file)
index 0000000..adf3186
--- /dev/null
@@ -0,0 +1,218 @@
+/** @file inifcns.cpp
+ *
+ *  Implementation of GiNaC's initially known functions. */
+
+#include <vector>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// dilogarithm
+//////////
+
+ex Li2_eval(ex const & x)
+{
+    if (x.is_zero())
+        return x;
+    if (x.is_equal(exONE()))
+        return power(Pi, 2) / 6;
+    if (x.is_equal(exMINUSONE()))
+        return -power(Pi, 2) / 12;
+    return Li2(x).hold();
+}
+
+REGISTER_FUNCTION(Li2, Li2_eval, NULL, NULL, NULL);
+
+//////////
+// trilogarithm
+//////////
+
+ex Li3_eval(ex const & x)
+{
+    if (x.is_zero())
+        return x;
+    return Li3(x).hold();
+}
+
+REGISTER_FUNCTION(Li3, Li3_eval, NULL, NULL, NULL);
+
+//////////
+// factorial
+//////////
+
+ex factorial_evalf(ex const & x)
+{
+    return factorial(x).hold();
+}
+
+ex factorial_eval(ex const & x)
+{
+    if (is_ex_exactly_of_type(x, numeric))
+        return factorial(ex_to_numeric(x));
+    else
+        return factorial(x).hold();
+}
+
+REGISTER_FUNCTION(factorial, factorial_eval, factorial_evalf, NULL, NULL);
+
+//////////
+// binomial
+//////////
+
+ex binomial_evalf(ex const & x, ex const & y)
+{
+    return binomial(x, y).hold();
+}
+
+ex binomial_eval(ex const & x, ex const &y)
+{
+    if (is_ex_exactly_of_type(x, numeric) && is_ex_exactly_of_type(y, numeric))
+        return binomial(ex_to_numeric(x), ex_to_numeric(y));
+    else
+        return binomial(x, y).hold();
+}
+
+REGISTER_FUNCTION(binomial, binomial_eval, binomial_evalf, NULL, NULL);
+
+//////////
+// Order term function (for truncated power series)
+//////////
+
+ex Order_eval(ex const & x)
+{
+       if (is_ex_exactly_of_type(x, numeric)) {
+
+               // O(c)=O(1)
+               return Order(exONE()).hold();
+
+       } else if (is_ex_exactly_of_type(x, mul)) {
+
+               mul *m = static_cast<mul *>(x.bp);
+               if (is_ex_exactly_of_type(m->op(m->nops() - 1), numeric)) {
+
+                       // O(c*expr)=O(expr)
+                       return Order(x / m->op(m->nops() - 1)).hold();
+               }
+       }
+       return Order(x).hold();
+}
+
+ex Order_series(ex const & x, symbol const & s, ex const & point, int order)
+{
+       // Just wrap the function into a series object
+       epvector new_seq;
+       new_seq.push_back(expair(Order(exONE()), numeric(min(x.ldegree(s), order))));
+       return series(s, point, new_seq);
+}
+
+REGISTER_FUNCTION(Order, Order_eval, NULL, NULL, Order_series);
+
+/** linear solve. */
+ex lsolve(ex eqns, ex symbols)
+{
+    // solve a system of linear equations
+    if (eqns.info(info_flags::relation_equal)) {
+        if (!symbols.info(info_flags::symbol)) {
+            throw(std::invalid_argument("lsolve: 2nd argument must be a symbol"));
+        }
+        ex sol=lsolve(lst(eqns),lst(symbols));
+        
+        ASSERT(sol.nops()==1);
+        ASSERT(is_ex_exactly_of_type(sol.op(0),relational));
+        
+        return sol.op(0).op(1); // return rhs of first solution
+    }
+    
+    // syntax checks
+    if (!eqns.info(info_flags::list)) {
+        throw(std::invalid_argument("lsolve: 1st argument must be a list"));
+    }
+    for (int i=0; i<eqns.nops(); i++) {
+        if (!eqns.op(i).info(info_flags::relation_equal)) {
+            throw(std::invalid_argument("lsolve: 1st argument must be a list of equations"));
+        }
+    }
+    if (!symbols.info(info_flags::list)) {
+        throw(std::invalid_argument("lsolve: 2nd argument must be a list"));
+    }
+    for (int 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"));
+        }
+    }
+    
+    // build matrix from equation system
+    matrix sys(eqns.nops(),symbols.nops());
+    matrix rhs(eqns.nops(),1);
+    matrix vars(symbols.nops(),1);
+
+    for (int r=0; r<eqns.nops(); r++) {
+        ex eq=eqns.op(r).op(0)-eqns.op(r).op(1); // lhs-rhs==0
+        ex linpart=eq;
+        for (int c=0; c<symbols.nops(); c++) {
+            ex co=eq.coeff(ex_to_symbol(symbols.op(c)),1);
+            linpart -= co*symbols.op(c);
+            sys.set(r,c,co);
+        }
+        linpart=linpart.expand();
+        rhs.set(r,0,-linpart);
+    }
+    
+    // test if system is linear and fill vars matrix
+    for (int i=0; i<symbols.nops(); i++) {
+        vars.set(i,0,symbols.op(i));
+        if (sys.has(symbols.op(i))) {
+            throw(std::logic_error("lsolve: system is not linear"));
+        }
+        if (rhs.has(symbols.op(i))) {
+            throw(std::logic_error("lsolve: system is not linear"));
+        }
+    }
+    
+    //matrix solution=sys.solve(rhs);
+    matrix solution;
+    try {
+        solution=sys.fraction_free_elim(vars,rhs);
+    } catch (runtime_error const & e) {
+        // probably singular matrix (or other error)
+        // return empty solution list
+        cerr << e.what() << endl;
+        return lst();
+    }
+    
+    // return a list of equations
+    if (solution.cols()!=1) {
+        throw(std::runtime_error("lsolve: strange number of columns returned from matrix::solve"));
+    }
+    if (solution.rows()!=symbols.nops()) {
+        cout << "symbols.nops()=" << symbols.nops() << endl;
+        cout << "solution.rows()=" << solution.rows() << endl;
+        throw(std::runtime_error("lsolve: strange number of rows returned from matrix::solve"));
+    }
+    
+    // return list of the form lst(var1==sol1,var2==sol2,...)
+    lst sollist;
+    for (int i=0; i<symbols.nops(); i++) {
+        sollist.append(symbols.op(i)==solution(i,0));
+    }
+    
+    return sollist;
+}
+
+/** non-commutative power. */
+ex ncpower(ex basis, unsigned exponent)
+{
+    if (exponent==0) {
+        return exONE();
+    }
+
+    exvector v;
+    v.reserve(exponent);
+    for (unsigned i=0; i<exponent; ++i) {
+        v.push_back(basis);
+    }
+
+    return ncmul(v,1);
+}
+
diff --git a/ginac/inifcns.h b/ginac/inifcns.h
new file mode 100644 (file)
index 0000000..c1f1f24
--- /dev/null
@@ -0,0 +1,83 @@
+/** @file inifcns.h
+ *
+ *  Interface to GiNaC's initially known functions. */
+
+#ifndef _INIFCNS_H_
+#define _INIFCNS_H_
+
+#include "numeric.h"
+#include "function.h"
+
+/** Sine. */
+DECLARE_FUNCTION_1P(sin)
+
+/** Cosine. */
+DECLARE_FUNCTION_1P(cos)
+
+/** Tangent. */
+DECLARE_FUNCTION_1P(tan)
+
+/** Exponential function. */
+DECLARE_FUNCTION_1P(exp)
+
+/** Natural logarithm. */
+DECLARE_FUNCTION_1P(log)
+
+/** Inverse sine (arc sine). */
+DECLARE_FUNCTION_1P(asin)
+
+/** Inverse cosine (arc cosine). */
+DECLARE_FUNCTION_1P(acos)
+
+/** Inverse tangent (arc tangent). */
+DECLARE_FUNCTION_1P(atan)
+
+/** Inverse tangent with two arguments. */
+DECLARE_FUNCTION_2P(atan2)
+
+/** Hyperbolic Sine. */
+DECLARE_FUNCTION_1P(sinh)
+
+/** Hyperbolic Cosine. */
+DECLARE_FUNCTION_1P(cosh)
+
+/** Hyperbolic Tangent. */
+DECLARE_FUNCTION_1P(tanh)
+
+/** Inverse hyperbolic Sine (area hyperbolic sine). */
+DECLARE_FUNCTION_1P(asinh)
+
+/** Inverse hyperbolic Cosine (area hyperbolic cosine). */
+DECLARE_FUNCTION_1P(acosh)
+
+/** Inverse hyperbolic Tangent (area hyperbolic tangent). */
+DECLARE_FUNCTION_1P(atanh)
+
+/** Dilogarithm. */
+DECLARE_FUNCTION_1P(Li2)
+
+/** Trilogarithm. */
+DECLARE_FUNCTION_1P(Li3)
+
+/** Gamma function. */
+DECLARE_FUNCTION_1P(gamma)
+
+/** Factorial function. */
+DECLARE_FUNCTION_1P(factorial)
+
+/** Binomial function. */
+DECLARE_FUNCTION_2P(binomial)
+
+/** Order term function (for truncated power series). */
+DECLARE_FUNCTION_1P(Order)
+
+ex lsolve(ex eqns,ex symbols);
+
+ex ncpower(ex basis, unsigned exponent);
+
+inline bool is_order_function(ex const & e)
+{
+       return is_ex_the_function(e, Order);
+}
+
+#endif // ndef _INIFCNS_H_
diff --git a/ginac/inifcns_gamma.cpp b/ginac/inifcns_gamma.cpp
new file mode 100644 (file)
index 0000000..b94ee27
--- /dev/null
@@ -0,0 +1,80 @@
+/** @file inifcns_gamma.cpp
+ *
+ *  Implementation of Gamma function and some related stuff. */
+
+#include <vector>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// gamma function
+//////////
+
+/** Evaluation of gamma(x). Knows about integer arguments, half-integer
+ *  arguments and that's it. Somebody ought to provide some good numerical
+ *  evaluation some day...
+ *
+ *  @exception fail_numeric("complex_infinity") or something similar... */
+ex gamma_eval(ex const & x)
+{
+    if ( x.info(info_flags::numeric) ) {
+
+        // trap integer arguments:
+        if ( x.info(info_flags::integer) ) {
+            // gamma(n+1) -> n! for postitive n
+            if ( x.info(info_flags::posint) ) {
+                return factorial(ex_to_numeric(x).sub(numONE()));
+            } else {
+                return numZERO();  // Infinity. Throw? What?
+            }
+        }
+        // trap half integer arguments:
+        if ( (x*2).info(info_flags::integer) ) {
+            // trap positive x=(n+1/2)
+            // gamma(n+1/2) -> Pi^(1/2)*(1*3*..*(2*n-1))/(2^n)
+            if ( (x*2).info(info_flags::posint) ) {
+                numeric n = ex_to_numeric(x).sub(numHALF());
+                numeric coefficient = doublefactorial(n.mul(numTWO()).sub(numONE()));
+                coefficient = coefficient.div(numTWO().power(n));
+                return mul(coefficient,power(Pi,numHALF()));
+            } else {
+                // trap negative x=(-n+1/2)
+                // gamma(-n+1/2) -> Pi^(1/2)*(-2)^n/(1*3*..*(2*n-1))
+                numeric n = abs(ex_to_numeric(x).sub(numHALF()));
+                numeric coefficient = numeric(-2).power(n);
+                coefficient = coefficient.div(doublefactorial(n.mul(numTWO()).sub(numONE())));;
+                return mul(coefficient,power(Pi,numHALF()));
+            }
+        }
+    }
+    return gamma(x).hold();
+}    
+    
+ex gamma_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+        TYPECHECK(x,numeric)
+    END_TYPECHECK(gamma(x))
+    
+    return gamma(ex_to_numeric(x));
+}
+
+ex gamma_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+
+    return power(x, -1);       //!!
+}
+
+ex gamma_series(ex const & x, symbol const & s, ex const & point, int order)
+{
+       //!! Only handle one special case for now...
+       if (x.is_equal(s) && point.is_zero()) {
+               ex e = 1 / s - EulerGamma + s * (power(Pi, 2) / 12 + power(EulerGamma, 2) / 2) + Order(power(s, 2));
+               return e.series(s, point, order);
+       } else
+               throw(std::logic_error("don't know the series expansion of this particular gamma function"));
+}
+
+REGISTER_FUNCTION(gamma, gamma_eval, gamma_evalf, gamma_diff, gamma_series);
diff --git a/ginac/inifcns_trans.cpp b/ginac/inifcns_trans.cpp
new file mode 100644 (file)
index 0000000..c67d833
--- /dev/null
@@ -0,0 +1,717 @@
+/** @file inifcns_trans.cpp
+ *
+ *  Implementation of transcendental (and trigonometric and hyperbolic)
+ *  functions. */
+
+#include <vector>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// exponential function
+//////////
+
+ex exp_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+        TYPECHECK(x,numeric)
+    END_TYPECHECK(exp(x))
+    
+    return exp(ex_to_numeric(x)); // -> numeric exp(numeric)
+}
+
+ex exp_eval(ex const & x)
+{
+    // exp(0) -> 1
+    if (x.is_zero()) {
+        return exONE();
+    }
+    // exp(n*Pi*I/2) -> {+1|+I|-1|-I}
+    ex TwoExOverPiI=(2*x)/(Pi*I);
+    if (TwoExOverPiI.info(info_flags::integer)) {
+        numeric z=mod(ex_to_numeric(TwoExOverPiI),numeric(4));
+        if (z.is_equal(numZERO()))
+            return exONE();
+        if (z.is_equal(numONE()))
+            return ex(I);
+        if (z.is_equal(numTWO()))
+            return exMINUSONE();
+        if (z.is_equal(numTHREE()))
+            return ex(-I);
+    }
+    // exp(log(x)) -> x
+    if (is_ex_the_function(x, log))
+        return x.op(0);
+    
+    // exp(float)
+    if (x.info(info_flags::numeric) && !x.info(info_flags::rational))
+        return exp_evalf(x);
+    
+    return exp(x).hold();
+}    
+
+ex exp_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+
+    return exp(x);
+}
+
+REGISTER_FUNCTION(exp, exp_eval, exp_evalf, exp_diff, NULL);
+
+//////////
+// natural logarithm
+//////////
+
+ex log_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+        TYPECHECK(x,numeric)
+    END_TYPECHECK(log(x))
+    
+    return log(ex_to_numeric(x)); // -> numeric log(numeric)
+}
+
+ex log_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // log(1) -> 0
+        if (x.is_equal(exONE()))
+            return exZERO();
+        // log(-1) -> I*Pi
+        if (x.is_equal(exMINUSONE()))
+            return (I*Pi);
+        // log(I) -> Pi*I/2
+        if (x.is_equal(I))
+            return (I*Pi*numeric(1,2));
+        // log(-I) -> -Pi*I/2
+        if (x.is_equal(-I))
+            return (I*Pi*numeric(-1,2));
+        // log(0) -> throw singularity
+        if (x.is_equal(exZERO()))
+            throw(std::domain_error("log_eval(): log(0)"));
+        // log(float)
+        if (!x.info(info_flags::rational))
+            return log_evalf(x);
+    }
+    
+    return log(x).hold();
+}    
+
+ex log_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+
+    return power(x, -1);
+}
+
+REGISTER_FUNCTION(log, log_eval, log_evalf, log_diff, NULL);
+
+//////////
+// sine (trigonometric function)
+//////////
+
+ex sin_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(sin(x))
+    
+    return sin(ex_to_numeric(x)); // -> numeric sin(numeric)
+}
+
+ex sin_eval(ex const & x)
+{
+    // sin(n*Pi) -> 0
+    ex xOverPi=x/Pi;
+    if (xOverPi.info(info_flags::integer))
+        return exZERO();
+    
+    // sin((2n+1)*Pi/2) -> {+|-}1
+    ex xOverPiMinusHalf=xOverPi-exHALF();
+    if (xOverPiMinusHalf.info(info_flags::even))
+        return exONE();
+    else if (xOverPiMinusHalf.info(info_flags::odd))
+        return exMINUSONE();
+    
+    if (is_ex_exactly_of_type(x, function)) {
+        ex t=x.op(0);
+        // sin(asin(x)) -> x
+        if (is_ex_the_function(x, asin))
+            return t;
+        // sin(acos(x)) -> (1-x^2)^(1/2)
+        if (is_ex_the_function(x, acos))
+            return power(exONE()-power(t,exTWO()),exHALF());
+        // sin(atan(x)) -> x*(1+x^2)^(-1/2)
+        if (is_ex_the_function(x, atan))
+            return t*power(exONE()+power(t,exTWO()),exMINUSHALF());
+    }
+    
+    // sin(float) -> float
+    if (x.info(info_flags::numeric) && !x.info(info_flags::rational))
+        return sin_evalf(x);
+    
+    return sin(x).hold();
+}
+
+ex sin_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return cos(x);
+}
+
+REGISTER_FUNCTION(sin, sin_eval, sin_evalf, sin_diff, NULL);
+
+//////////
+// cosine (trigonometric function)
+//////////
+
+ex cos_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+        TYPECHECK(x,numeric)
+    END_TYPECHECK(cos(x))
+    
+    return cos(ex_to_numeric(x)); // -> numeric cos(numeric)
+}
+
+ex cos_eval(ex const & x)
+{
+    // cos(n*Pi) -> {+|-}1
+    ex xOverPi=x/Pi;
+    if (xOverPi.info(info_flags::even))
+        return exONE();
+    else if (xOverPi.info(info_flags::odd))
+        return exMINUSONE();
+    
+    // cos((2n+1)*Pi/2) -> 0
+    ex xOverPiMinusHalf=xOverPi-exHALF();
+    if (xOverPiMinusHalf.info(info_flags::integer))
+        return exZERO();
+    
+    if (is_ex_exactly_of_type(x, function)) {
+        ex t=x.op(0);
+        // cos(acos(x)) -> x
+        if (is_ex_the_function(x, acos))
+            return t;
+        // cos(asin(x)) -> (1-x^2)^(1/2)
+        if (is_ex_the_function(x, asin))
+            return power(exONE()-power(t,exTWO()),exHALF());
+        // cos(atan(x)) -> (1+x^2)^(-1/2)
+        if (is_ex_the_function(x, atan))
+            return power(exONE()+power(t,exTWO()),exMINUSHALF());
+    }
+    
+    // cos(float) -> float
+    if (x.info(info_flags::numeric) && !x.info(info_flags::rational))
+        return cos_evalf(x);
+    
+    return cos(x).hold();
+}
+
+ex cos_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+
+    return numMINUSONE()*sin(x);
+}
+
+REGISTER_FUNCTION(cos, cos_eval, cos_evalf, cos_diff, NULL);
+
+//////////
+// tangent (trigonometric function)
+//////////
+
+ex tan_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
+    
+    return tan(ex_to_numeric(x));
+}
+
+ex tan_eval(ex const & x)
+{
+    // tan(n*Pi/3) -> {0|3^(1/2)|-(3^(1/2))}
+    ex ThreeExOverPi=numTHREE()*x/Pi;
+    if (ThreeExOverPi.info(info_flags::integer)) {
+        numeric z=mod(ex_to_numeric(ThreeExOverPi),numeric(3));
+        if (z.is_equal(numZERO()))
+            return exZERO();
+        if (z.is_equal(numONE()))
+            return power(exTHREE(),exHALF());
+        if (z.is_equal(numTWO()))
+            return -power(exTHREE(),exHALF());
+    }
+    
+    // tan((2n+1)*Pi/2) -> throw
+    ex ExOverPiMinusHalf=x/Pi-exHALF();
+    if (ExOverPiMinusHalf.info(info_flags::integer))
+        throw (std::domain_error("tan_eval(): infinity"));
+    
+    if (is_ex_exactly_of_type(x, function)) {
+        ex t=x.op(0);
+        // tan(atan(x)) -> x
+        if (is_ex_the_function(x, atan))
+            return t;
+        // tan(asin(x)) -> x*(1+x^2)^(-1/2)
+        if (is_ex_the_function(x, asin))
+            return t*power(exONE()-power(t,exTWO()),exMINUSHALF());
+        // tan(acos(x)) -> (1-x^2)^(1/2)/x
+        if (is_ex_the_function(x, acos))
+            return power(t,exMINUSONE())*power(exONE()-power(t,exTWO()),exHALF());
+    }
+    
+    // tan(float) -> float
+    if (x.info(info_flags::numeric) && !x.info(info_flags::rational)) {
+        return tan_evalf(x);
+    }
+    
+    return tan(x).hold();
+}
+
+ex tan_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return (1+power(tan(x),exTWO()));
+}
+
+REGISTER_FUNCTION(tan, tan_eval, tan_evalf, tan_diff, NULL);
+
+//////////
+// inverse sine (arc sine)
+//////////
+
+ex asin_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(asin(x))
+    
+    return asin(ex_to_numeric(x)); // -> numeric asin(numeric)
+}
+
+ex asin_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // asin(0) -> 0
+        if (x.is_zero())
+            return x;
+        // asin(1/2) -> Pi/6
+        if (x.is_equal(exHALF()))
+            return numeric(1,6)*Pi;
+        // asin(1) -> Pi/2
+        if (x.is_equal(exONE()))
+            return numeric(1,2)*Pi;
+        // asin(-1/2) -> -Pi/6
+        if (x.is_equal(exMINUSHALF()))
+            return numeric(-1,6)*Pi;
+        // asin(-1) -> -Pi/2
+        if (x.is_equal(exMINUSONE()))
+            return numeric(-1,2)*Pi;
+        // asin(float) -> float
+        if (!x.info(info_flags::rational))
+            return asin_evalf(x);
+    }
+    
+    return asin(x).hold();
+}
+
+ex asin_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return power(1-power(x,exTWO()),exMINUSHALF());
+}
+
+REGISTER_FUNCTION(asin, asin_eval, asin_evalf, asin_diff, NULL);
+
+//////////
+// inverse cosine (arc cosine)
+//////////
+
+ex acos_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(acos(x))
+    
+    return acos(ex_to_numeric(x)); // -> numeric acos(numeric)
+}
+
+ex acos_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // acos(1) -> 0
+        if (x.is_equal(exONE()))
+            return exZERO();
+        // acos(1/2) -> Pi/3
+        if (x.is_equal(exHALF()))
+            return numeric(1,3)*Pi;
+        // acos(0) -> Pi/2
+        if (x.is_zero())
+            return numeric(1,2)*Pi;
+        // acos(-1/2) -> 2/3*Pi
+        if (x.is_equal(exMINUSHALF()))
+            return numeric(2,3)*Pi;
+        // acos(-1) -> Pi
+        if (x.is_equal(exMINUSONE()))
+            return Pi;
+        // acos(float) -> float
+        if (!x.info(info_flags::rational))
+            return acos_evalf(x);
+    }
+    
+    return acos(x).hold();
+}
+
+ex acos_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return numMINUSONE()*power(1-power(x,exTWO()),exMINUSHALF());
+}
+
+REGISTER_FUNCTION(acos, acos_eval, acos_evalf, acos_diff, NULL);
+
+//////////
+// inverse tangent (arc tangent)
+//////////
+
+ex atan_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+        TYPECHECK(x,numeric)
+    END_TYPECHECK(atan(x))
+    
+    return atan(ex_to_numeric(x)); // -> numeric atan(numeric)
+}
+
+ex atan_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // atan(0) -> 0
+        if (x.is_equal(exZERO()))
+            return exZERO();
+        // atan(float) -> float
+        if (!x.info(info_flags::rational))
+            return atan_evalf(x);
+    }
+    
+    return atan(x).hold();
+}    
+
+ex atan_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+
+    return power(1+x*x, -1);
+}
+
+REGISTER_FUNCTION(atan, atan_eval, atan_evalf, atan_diff, NULL);
+
+//////////
+// inverse tangent (atan2(y,x))
+//////////
+
+ex atan2_evalf(ex const & y, ex const & x)
+{
+    BEGIN_TYPECHECK
+        TYPECHECK(y,numeric)
+        TYPECHECK(x,numeric)
+    END_TYPECHECK(atan2(y,x))
+    
+    return atan(ex_to_numeric(y),ex_to_numeric(x)); // -> numeric atan(numeric)
+}
+
+ex atan2_eval(ex const & y, ex const & x)
+{
+    if (y.info(info_flags::numeric) && !y.info(info_flags::rational) &&
+        x.info(info_flags::numeric) && !x.info(info_flags::rational)) {
+        return atan2_evalf(y,x);
+    }
+    
+    return atan2(y,x).hold();
+}    
+
+ex atan2_diff(ex const & y, ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param<2);
+
+    if (diff_param==0) {
+        // d/dy atan(y,x)
+        return power(x*(1+y*y/(x*x)),-1);
+    }
+    // d/dx atan(y,x)
+    return -y*power(x*x+y*y,-1);
+}
+
+REGISTER_FUNCTION(atan2, atan2_eval, atan2_evalf, atan2_diff, NULL);
+
+//////////
+// hyperbolic sine (trigonometric function)
+//////////
+
+ex sinh_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(sinh(x))
+    
+    return sinh(ex_to_numeric(x)); // -> numeric sinh(numeric)
+}
+
+ex sinh_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // sinh(0) -> 0
+        if (x.is_zero())
+            return exZERO();
+        // sinh(float) -> float
+        if (!x.info(info_flags::rational))
+            return sinh_evalf(x);
+    }
+    
+    if (is_ex_exactly_of_type(x, function)) {
+        ex t=x.op(0);
+        // sinh(asinh(x)) -> x
+        if (is_ex_the_function(x, asinh))
+            return t;
+        // sinh(acosh(x)) -> (x-1)^(1/2) * (x+1)^(1/2)
+        if (is_ex_the_function(x, acosh))
+            return power(t-exONE(),exHALF())*power(t+exONE(),exHALF());
+        // sinh(atanh(x)) -> x*(1-x^2)^(-1/2)
+        if (is_ex_the_function(x, atanh))
+            return t*power(exONE()-power(t,exTWO()),exMINUSHALF());
+    }
+    
+    return sinh(x).hold();
+}
+
+ex sinh_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return cosh(x);
+}
+
+REGISTER_FUNCTION(sinh, sinh_eval, sinh_evalf, sinh_diff, NULL);
+
+//////////
+// hyperbolic cosine (trigonometric function)
+//////////
+
+ex cosh_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(cosh(x))
+    
+    return cosh(ex_to_numeric(x)); // -> numeric cosh(numeric)
+}
+
+ex cosh_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // cosh(0) -> 1
+        if (x.is_zero())
+            return exONE();
+        // cosh(float) -> float
+        if (!x.info(info_flags::rational))
+            return cosh_evalf(x);
+    }
+    
+    if (is_ex_exactly_of_type(x, function)) {
+        ex t=x.op(0);
+        // cosh(acosh(x)) -> x
+        if (is_ex_the_function(x, acosh))
+            return t;
+        // cosh(asinh(x)) -> (1+x^2)^(1/2)
+        if (is_ex_the_function(x, asinh))
+            return power(exONE()+power(t,exTWO()),exHALF());
+        // cosh(atanh(x)) -> (1-x^2)^(-1/2)
+        if (is_ex_the_function(x, atanh))
+            return power(exONE()-power(t,exTWO()),exMINUSHALF());
+    }
+    
+    return cosh(x).hold();
+}
+
+ex cosh_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return sinh(x);
+}
+
+REGISTER_FUNCTION(cosh, cosh_eval, cosh_evalf, cosh_diff, NULL);
+
+//////////
+// hyperbolic tangent (trigonometric function)
+//////////
+
+ex tanh_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(tanh(x))
+    
+    return tanh(ex_to_numeric(x)); // -> numeric tanh(numeric)
+}
+
+ex tanh_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // tanh(0) -> 0
+        if (x.is_zero())
+            return exZERO();
+        // tanh(float) -> float
+        if (!x.info(info_flags::rational))
+            return tanh_evalf(x);
+    }
+    
+    if (is_ex_exactly_of_type(x, function)) {
+        ex t=x.op(0);
+        // tanh(atanh(x)) -> x
+        if (is_ex_the_function(x, atanh))
+            return t;
+        // tanh(asinh(x)) -> x*(1+x^2)^(-1/2)
+        if (is_ex_the_function(x, asinh))
+            return t*power(exONE()+power(t,exTWO()),exMINUSHALF());
+        // tanh(acosh(x)) -> (x-1)^(1/2)*(x+1)^(1/2)/x
+        if (is_ex_the_function(x, acosh))
+            return power(t-exONE(),exHALF())*power(t+exONE(),exHALF())*power(t,exMINUSONE());
+    }
+    
+    return tanh(x).hold();
+}
+
+ex tanh_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return exONE()-power(tanh(x),exTWO());
+}
+
+REGISTER_FUNCTION(tanh, tanh_eval, tanh_evalf, tanh_diff, NULL);
+
+//////////
+// inverse hyperbolic sine (trigonometric function)
+//////////
+
+ex asinh_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(asinh(x))
+    
+    return asinh(ex_to_numeric(x)); // -> numeric asinh(numeric)
+}
+
+ex asinh_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // asinh(0) -> 0
+        if (x.is_zero())
+            return exZERO();
+        // asinh(float) -> float
+        if (!x.info(info_flags::rational))
+            return asinh_evalf(x);
+    }
+    
+    return asinh(x).hold();
+}
+
+ex asinh_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return power(1+power(x,exTWO()),exMINUSHALF());
+}
+
+REGISTER_FUNCTION(asinh, asinh_eval, asinh_evalf, asinh_diff, NULL);
+
+//////////
+// inverse hyperbolic cosine (trigonometric function)
+//////////
+
+ex acosh_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(acosh(x))
+    
+    return acosh(ex_to_numeric(x)); // -> numeric acosh(numeric)
+}
+
+ex acosh_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // acosh(0) -> Pi*I/2
+        if (x.is_zero())
+            return Pi*I*numeric(1,2);
+        // acosh(1) -> 0
+        if (x.is_equal(exONE()))
+            return exZERO();
+        // acosh(-1) -> Pi*I
+        if (x.is_equal(exMINUSONE()))
+            return Pi*I;
+        // acosh(float) -> float
+        if (!x.info(info_flags::rational))
+            return acosh_evalf(x);
+    }
+    
+    return acosh(x).hold();
+}
+
+ex acosh_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return power(x-1,exMINUSHALF())*power(x+1,exMINUSHALF());
+}
+
+REGISTER_FUNCTION(acosh, acosh_eval, acosh_evalf, acosh_diff, NULL);
+
+//////////
+// inverse hyperbolic tangent (trigonometric function)
+//////////
+
+ex atanh_evalf(ex const & x)
+{
+    BEGIN_TYPECHECK
+       TYPECHECK(x,numeric)
+    END_TYPECHECK(atanh(x))
+    
+    return atanh(ex_to_numeric(x)); // -> numeric atanh(numeric)
+}
+
+ex atanh_eval(ex const & x)
+{
+    if (x.info(info_flags::numeric)) {
+        // atanh(0) -> 0
+        if (x.is_zero())
+            return exZERO();
+        // atanh({+|-}1) -> throw
+        if (x.is_equal(exONE()) || x.is_equal(exONE()))
+            throw (std::domain_error("atanh_eval(): infinity"));
+        // atanh(float) -> float
+        if (!x.info(info_flags::rational))
+            return atanh_evalf(x);
+    }
+    
+    return atanh(x).hold();
+}
+
+ex atanh_diff(ex const & x, unsigned diff_param)
+{
+    ASSERT(diff_param==0);
+    
+    return power(exONE()-power(x,exTWO()),exMINUSONE());
+}
+
+REGISTER_FUNCTION(atanh, atanh_eval, atanh_evalf, atanh_diff, NULL);
diff --git a/ginac/isospin.cpp b/ginac/isospin.cpp
new file mode 100644 (file)
index 0000000..c8a5804
--- /dev/null
@@ -0,0 +1,190 @@
+/** @file isospin.cpp
+ *
+ *  Implementation of GiNaC's isospin objects.
+ *  No real implementation yet, to be done.     */
+
+#include <string>
+
+#include "ginac.h"
+#include "utils.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+isospin::isospin()
+{
+    debugmsg("isospin default constructor",LOGLEVEL_CONSTRUCT);
+    serial=next_serial++;
+    name=autoname_prefix()+ToString(serial);
+    tinfo_key=TINFO_ISOSPIN;
+}
+
+isospin::~isospin()
+{
+    debugmsg("isospin destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+isospin::isospin(isospin const & other)
+{
+    debugmsg("isospin copy constructor",LOGLEVEL_CONSTRUCT);
+    copy (other);
+}
+
+isospin const & isospin::operator=(isospin const & other)
+{
+    debugmsg("isospin operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void isospin::copy(isospin const & other)
+{
+    indexed::copy(other);
+    name=other.name;
+    serial=other.serial;
+}
+
+void isospin::destroy(bool call_parent)
+{
+    if (call_parent) {
+        indexed::destroy(call_parent);
+    }
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+isospin::isospin(string const & initname)
+{
+    debugmsg("isospin constructor from string",LOGLEVEL_CONSTRUCT);
+    name=initname;
+    serial=next_serial++;
+    tinfo_key=TINFO_ISOSPIN;
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * isospin::duplicate() const
+{
+    debugmsg("isospin duplicate",LOGLEVEL_DUPLICATE);
+    return new isospin(*this);
+}
+
+void isospin::printraw(ostream & os) const
+{
+    debugmsg("isospin printraw",LOGLEVEL_PRINT);
+    os << "isospin(" << "name=" << name << ",serial=" << serial
+       << ",indices=";
+    printrawindices(os);
+    os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+}
+
+void isospin::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("isospin printtree",LOGLEVEL_PRINT);
+    os << string(indent,' ') << name << " (isospin): "
+       << "serial=" << serial << ","
+       << seq.size() << "indices=";
+    printtreeindices(os,indent);
+    os << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void isospin::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("isospin print",LOGLEVEL_PRINT);
+    os << name;
+    printindices(os);
+}
+
+void isospin::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("isospin print csrc",LOGLEVEL_PRINT);
+    print(os,upper_precedence);
+}
+
+bool isospin::info(unsigned inf) const
+{
+    return indexed::info(inf);
+}
+
+// protected
+
+int isospin::compare_same_type(basic const & other) const
+{
+    ASSERT(other.tinfo() == TINFO_ISOSPIN);
+    const isospin *o = static_cast<const isospin *>(&other);
+    if (serial==o->serial) {
+        return indexed::compare_same_type(other);
+    }
+    return serial < o->serial ? -1 : 1;
+}
+
+ex isospin::simplify_ncmul(exvector const & v) const
+{
+    return simplified_ncmul(v);
+}
+
+unsigned isospin::calchash(void) const
+{
+    hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555556U ^
+                                                  golden_ratio_hash(tinfo_key) ^
+                                                  serial));
+    setflag(status_flags::hash_calculated);
+    return hashvalue;
+}
+
+//////////
+// virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+void isospin::setname(string const & n)
+{
+    name=n;
+}
+
+// private
+
+string & isospin::autoname_prefix(void)
+{
+    static string * s=new string("isospin");
+    return *s;
+}
+
+//////////
+// static member variables
+//////////
+
+// private
+
+unsigned isospin::next_serial=0;
+
+//////////
+// global constants
+//////////
+
+const isospin some_isospin;
+type_info const & typeid_isospin=typeid(some_isospin);
+
diff --git a/ginac/isospin.h b/ginac/isospin.h
new file mode 100644 (file)
index 0000000..3a8e930
--- /dev/null
@@ -0,0 +1,75 @@
+/** @file isospin.h
+ *
+ *  Interface to GiNaC's isospin objects. */
+
+#ifndef _ISOSPIN_H_
+#define _ISOSPIN_H_
+
+#include <string>
+
+class isospin;
+
+#include "indexed.h"
+
+/** Base class for isospin object */
+class isospin : public indexed
+{
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    isospin();
+    ~isospin();
+    isospin(isospin const & other);
+    isospin const & operator=(isospin const & other);
+protected:
+    void copy(isospin const & other); 
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    explicit isospin(string const & initname);
+
+    // functions overriding virtual functions from base classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    ex simplify_ncmul(exvector const & v) const;
+    unsigned calchash(void) const;
+
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+public:
+    void setname(string const & n);
+private:
+    string & autoname_prefix(void);
+
+// member variables
+
+protected:
+    string name;
+    unsigned serial; // unique serial number for comparision
+private:
+    static unsigned next_serial;
+};
+
+// global constants
+
+extern const isospin some_isospin;
+extern type_info const & typeid_isospin;
+
+// macros
+
+#define ex_to_isospin(X) static_cast<isospin const &>(*(X).bp)
+
+#endif // ndef _ISOSPIN_H_
+
+
diff --git a/ginac/lorentzidx.cpp b/ginac/lorentzidx.cpp
new file mode 100644 (file)
index 0000000..e53d8a8
--- /dev/null
@@ -0,0 +1,234 @@
+/** @file lorentzidx.cpp
+ *
+ *  Implementation of GiNaC's lorentz indices. */
+
+#include <stdexcept>
+
+#include "ginac.h"
+#include "utils.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+lorentzidx::lorentzidx() : orthogonal_only(false), dim_parallel_space(0)
+{
+    debugmsg("lorentzidx default constructor",LOGLEVEL_CONSTRUCT);
+    // serial is incremented in idx::idx()
+    name="mu"+ToString(serial);
+    tinfo_key=TINFO_LORENTZIDX;
+}
+
+lorentzidx::~lorentzidx() 
+{
+    debugmsg("lorentzidx destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+lorentzidx::lorentzidx(lorentzidx const & other)
+{
+    debugmsg("lorentzidx copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+lorentzidx const & lorentzidx::operator=(lorentzidx const & other)
+{
+    debugmsg("lorentzidx operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void lorentzidx::copy(lorentzidx const & other)
+{
+    idx::copy(other);
+    orthogonal_only=other.orthogonal_only;
+    dim_parallel_space=other.dim_parallel_space;
+}
+
+void lorentzidx::destroy(bool call_parent)
+{
+    if (call_parent) idx::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+lorentzidx::lorentzidx(bool cov, bool oonly, unsigned dimp) :
+    idx(cov), orthogonal_only(oonly), dim_parallel_space(dimp)
+{
+    debugmsg("lorentzidx constructor from bool",LOGLEVEL_CONSTRUCT);
+    // serial is incremented in idx::idx(bool)
+    if (oonly) {
+        name="muorth"+ToString(serial);
+    } else {
+        name="mu"+ToString(serial);
+    }
+    tinfo_key=TINFO_LORENTZIDX;
+}
+
+lorentzidx::lorentzidx(string const & n, bool cov, bool oonly, unsigned dimp)
+    : idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp)
+{
+    debugmsg("lorentzidx constructor from string,bool,bool,unsigned",
+             LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_LORENTZIDX;
+}
+
+lorentzidx::lorentzidx(char const * n, bool cov, bool oonly, unsigned dimp)
+    : idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp)
+{
+    debugmsg("lorentzidx constructor from char*,bool,bool,unsigned",
+             LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_LORENTZIDX;
+}
+
+lorentzidx::lorentzidx(unsigned const v, bool cov) : idx(v,cov),
+    orthogonal_only(false), dim_parallel_space(0)
+{
+    debugmsg("lorentzidx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_LORENTZIDX;
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * lorentzidx::duplicate() const
+{
+    debugmsg("lorentzidx duplicate",LOGLEVEL_DUPLICATE);
+    return new lorentzidx(*this);
+}
+
+void lorentzidx::printraw(ostream & os) const
+{
+    debugmsg("lorentzidx printraw",LOGLEVEL_PRINT);
+
+    os << "lorentzidx(";
+
+    if (symbolic) {
+        os << "symbolic,name=" << name;
+    } else {
+        os << "non symbolic,value=" << value;
+    }
+
+    if (covariant) {
+        os << ",covariant";
+    } else {
+        os << ",contravariant";
+    }
+
+    if (orthogonal_only) {
+        os << ",only orthogonal components at " << dim_parallel_space
+           << " parallel dimensions";
+    } else {
+        os << ",parallel and orthogonal components";
+    }
+
+    os << ",serial=" << serial;
+    os << ",hash=" << hashvalue << ",flags=" << flags;
+    os << ")";
+}
+
+void lorentzidx::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("lorentzidx printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "lorentzidx: ";
+
+    if (symbolic) {
+        os << "symbolic,name=" << name;
+    } else {
+        os << "non symbolic,value=" << value;
+    }
+
+    if (covariant) {
+        os << ",covariant";
+    } else {
+        os << ",contravariant";
+    }
+
+    if (orthogonal_only) {
+        os << ",only orthogonal components at " << dim_parallel_space
+           << " parallel dimensions";
+    } else {
+        os << ",parallel and orthogonal components";
+    }
+
+    os << ", serial=" << serial
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void lorentzidx::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("lorentzidx print",LOGLEVEL_PRINT);
+
+    if (covariant) {
+        os << "_";
+    } else {
+        os << "~";
+    }
+    if (symbolic) {
+        os << name;
+    } else {
+        os << value;
+    }
+}
+
+bool lorentzidx::info(unsigned inf) const
+{
+    if (inf==info_flags::lorentzidx) return true;
+    return idx::info(inf);
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+
+lorentzidx lorentzidx::create_anonymous_representative(void) const
+{
+    ASSERT(is_symbolic());
+    lorentzidx i_copy(*this);
+    i_copy.serial=0;
+    i_copy.name="anonymous_representative";
+    i_copy.covariant=false;
+    i_copy.clearflag(status_flags::dynallocated|
+                     status_flags::hash_calculated);
+    return i_copy;
+}
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const lorentzidx some_lorentzidx;
+type_info const & typeid_lorentzidx=typeid(some_lorentzidx);
+
+
+
diff --git a/ginac/lorentzidx.h b/ginac/lorentzidx.h
new file mode 100644 (file)
index 0000000..99eae08
--- /dev/null
@@ -0,0 +1,71 @@
+/** @file lorentzidx.h
+ *
+ *  Interface to GiNaC's lorentz indices. */
+
+#ifndef _LORENTZIDX_H_
+#define _LORENTZIDX_H_
+
+#include <string>
+#include <vector>
+
+#include "idx.h"
+
+class lorentzidx : public idx
+{
+    friend class simp_lor;
+    friend class scalar_products;
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    lorentzidx();
+    ~lorentzidx();
+    lorentzidx (lorentzidx const & other);
+    lorentzidx const & operator=(lorentzidx const & other);
+protected:
+    void copy(lorentzidx const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    explicit lorentzidx(bool cov, bool oonly=false, unsigned dimp=0);
+    explicit lorentzidx(string const & n, bool cov=false,
+                        bool oonly=false, unsigned dimp=0);
+    explicit lorentzidx(char const * n, bool cov=false,
+                        bool oonly=false, unsigned dimp=0);
+    explicit lorentzidx(unsigned const v, bool cov=false);
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+
+    // new virtual functions which can be overridden by derived classes
+    // none
+
+    // non-virtual functions in this class
+public:
+    bool is_orthogonal_only(void) const { return orthogonal_only; }
+    unsigned get_dim_parallel_space(void) const { return dim_parallel_space; }
+    lorentzidx create_anonymous_representative(void) const; 
+
+    // member variables
+protected:
+    bool orthogonal_only;
+    unsigned dim_parallel_space;
+};
+
+// global constants
+
+extern const lorentzidx some_lorentzidx;
+extern type_info const & typeid_lorentzidx;
+
+// macros
+
+#define ex_to_lorentzidx(X) (static_cast<lorentzidx const &>(*(X).bp))
+
+#endif // ndef _LORENTZIDX_H_
diff --git a/ginac/lst.cpp b/ginac/lst.cpp
new file mode 100644 (file)
index 0000000..550d886
--- /dev/null
@@ -0,0 +1,611 @@
+/** @file lst.cpp
+ *
+ *  Implementation of GiNaC's lst. 
+ *  This file was generated automatically by container.pl.
+ *  Please do not modify it directly, edit the perl script instead!
+ *  container.pl options: $CONTAINER=lst
+ *                        $STLHEADER=list
+ *                        $reserve=0
+ *                        $prepend=1
+ *                        $let_op=1
+ *                        $open_bracket=[
+ *                        $close_bracket=] */
+
+#include <iostream>
+#include <stdexcept>
+
+#include "ginac.h"
+
+#define RESERVE(s,size) // no reserve needed for list
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+lst::lst() : basic(TINFO_LST)
+{
+    debugmsg("lst default constructor",LOGLEVEL_CONSTRUCT);
+}
+
+lst::~lst()
+{
+    debugmsg("lst destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+lst::lst(lst const & other)
+{
+    debugmsg("lst copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+lst const & lst::operator=(lst const & other)
+{
+    debugmsg("lst operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void lst::copy(lst const & other)
+{
+    basic::copy(other);
+    seq=other.seq;
+}
+
+void lst::destroy(bool call_parent)
+{
+    seq.clear();
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+lst::lst(exlist const & s, bool discardable) :  basic(TINFO_LST)
+{
+    debugmsg("lst constructor from exlist",
+             LOGLEVEL_CONSTRUCT);
+    if (discardable) {
+        seq.swap(const_cast<exlist &>(s));
+    } else {
+        seq=s;
+    }
+}
+
+lst::lst(exlist * vp) : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from exlist *",LOGLEVEL_CONSTRUCT);
+    ASSERT(vp!=0);
+    seq.swap(*vp);
+    delete vp;
+}
+
+lst::lst(ex const & e1) :  basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 1 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,1);
+    seq.push_back(e1);
+}
+
+lst::lst(ex const & e1, ex const & e2) : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 2 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,2);
+    seq.push_back(e1);
+    seq.push_back(e2);
+}
+
+lst::lst(ex const & e1, ex const & e2, ex const & e3)
+    : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 3 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,3);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+}
+
+lst::lst(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4) : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 4 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,4);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+}
+
+lst::lst(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5) : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 5 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,5);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+}
+
+lst::lst(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6)
+    : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 6 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,6);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+}
+
+lst::lst(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7) : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 7 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,7);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+}
+
+lst::lst(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8) : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 8 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,8);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+}
+
+lst::lst(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8, ex const & e9)
+    : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 9 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,9);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+    seq.push_back(e9);
+}
+
+lst::lst(ex const & e1, ex const & e2, ex const & e3,
+                     ex const & e4, ex const & e5, ex const & e6,
+                     ex const & e7, ex const & e8, ex const & e9,
+                     ex const &e10)
+    : basic(TINFO_LST)
+{
+    debugmsg("lst constructor from 10 ex",
+             LOGLEVEL_CONSTRUCT);
+    RESERVE(seq,10);
+    seq.push_back(e1);
+    seq.push_back(e2);
+    seq.push_back(e3);
+    seq.push_back(e4);
+    seq.push_back(e5);
+    seq.push_back(e6);
+    seq.push_back(e7);
+    seq.push_back(e8);
+    seq.push_back(e9);
+    seq.push_back(e10);
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * lst::duplicate() const
+{
+    debugmsg("lst duplicate",LOGLEVEL_DUPLICATE);
+    return new lst(*this);
+}
+
+void lst::printraw(ostream & os) const
+{
+    debugmsg("lst printraw",LOGLEVEL_PRINT);
+
+    os << "lst(";
+    for (exlist::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).bp->printraw(os);
+        os << ",";
+    }
+    os << ")";
+}
+
+void lst::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("lst print",LOGLEVEL_PRINT);
+    // always print brackets around seq, ignore upper_precedence
+    printseq(os,'[',',',']',precedence,precedence+1);
+}
+
+void lst::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("lst printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "type=" << typeid(*this).name()
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags
+       << ", nops=" << nops() << endl;
+    for (exlist::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        (*cit).printtree(os,indent+delta_indent);
+    }
+    os << string(indent+delta_indent,' ') << "=====" << endl;
+}
+
+// lst::info() will be implemented by user elsewhere";
+
+int lst::nops() const
+{
+    return seq.size();
+}
+
+ex & lst::let_op(int const i)
+{
+    ASSERT(i>=0);
+    ASSERT(i<nops());
+
+    exlist::iterator it=seq.begin();
+    for (int j=0; j<i; j++) {
+        ++it;
+    }
+    return *it;
+}
+
+
+ex lst::expand(unsigned options) const
+{
+    exlist s;
+    RESERVE(s,seq.size());
+    for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).expand(options));
+    }
+
+    return thislst(s);
+}
+
+// a lst 'has' an expression if it is this expression itself or a child 'has' it
+
+bool lst::has(ex const & other) const
+{
+    ASSERT(other.bp!=0);
+    if (is_equal(*other.bp)) return true;
+    for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        if ((*it).has(other)) return true;
+    }
+    return false;
+}
+
+ex lst::eval(int level) const
+{
+    if (level==1) {
+        return this->hold();
+    }
+    return thislst(evalchildren(level));
+}
+
+ex lst::evalf(int level) const
+{
+    return thislst(evalfchildren(level));
+}
+
+/** Implementation of ex::normal() for lsts. It normalizes the arguments
+ *  and replaces the lst by a temporary symbol.
+ *  @see ex::normal */
+ex lst::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    ex n=thislst(normalchildren(level));
+    return n.bp->basic::normal(sym_lst,repl_lst,level);
+}
+
+ex lst::diff(symbol const & s) const
+{
+    return thislst(diffchildren(s));
+}
+
+ex lst::subs(lst const & ls, lst const & lr) const
+{
+    exlist * vp=subschildren(ls,lr);
+    if (vp==0) {
+        return *this;
+    }
+    return thislst(vp);
+}
+
+// protected
+
+int lst::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,lst));
+    lst const & o=static_cast<lst const &>
+                                    (const_cast<basic &>(other));
+    int cmpval;
+    exlist::const_iterator it1=seq.begin();
+    exlist::const_iterator it2=o.seq.begin();
+
+    for (; (it1!=seq.end())&&(it2!=o.seq.end()); ++it1, ++it2) {
+        cmpval=(*it1).compare(*it2);
+        if (cmpval!=0) return cmpval;
+    }
+
+    if (it1==seq.end()) {
+        return (it2==o.seq.end() ? 0 : -1);
+    }
+
+    return 1;
+}
+
+bool lst::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,lst));
+    lst const & o=static_cast<lst const &>
+                                    (const_cast<basic &>(other));
+    if (seq.size()!=o.seq.size()) return false;
+
+    exlist::const_iterator it1=seq.begin();
+    exlist::const_iterator it2=o.seq.begin();
+
+    for (; it1!=seq.end(); ++it1, ++it2) {
+       if (!(*it1).is_equal(*it2)) return false;
+    }
+
+    return true;
+}
+
+unsigned lst::return_type(void) const
+{
+    return return_types::noncommutative_composite;
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// public
+
+lst & lst::append(ex const & b)
+{
+    ensure_if_modifiable();
+    seq.push_back(b);
+    return *this;
+}
+
+lst & lst::prepend(ex const & b)
+{
+    ensure_if_modifiable();
+    seq.push_front(b);
+    return *this;
+}
+
+
+// protected
+
+void lst::printseq(ostream & os, char openbracket, char delim,
+                         char closebracket, unsigned this_precedence,
+                         unsigned upper_precedence) const
+{
+    if (this_precedence<=upper_precedence) os << openbracket;
+    if (seq.size()!=0) {
+        exlist::const_iterator it,it_last;
+        it=seq.begin();
+        it_last=seq.end();
+        --it_last;
+        for (; it!=it_last; ++it) {
+            (*it).bp->print(os,this_precedence);
+            os << delim;
+        }
+        (*it).bp->print(os,this_precedence);
+    }
+    if (this_precedence<=upper_precedence) os << closebracket;
+}
+
+ex lst::thislst(exlist const & v) const
+{
+    return lst(v);
+}
+
+ex lst::thislst(exlist * vp) const
+{
+    return lst(vp);
+}
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+
+// none
+
+// protected
+
+bool lst::is_canonical() const
+{
+    if (seq.size()<=1) { return 1; }
+
+    exlist::const_iterator it=seq.begin();
+    exlist::const_iterator it_last=it;
+    for (++it; it!=seq.end(); it_last=it, ++it) {
+        if ((*it_last).compare(*it)>0) {
+            if ((*it_last).compare(*it)>0) {
+                cout << *it_last << ">" << *it << "\n";
+                return 0;
+               }
+        }
+    }
+    return 1;
+}
+
+
+exlist lst::evalchildren(int level) const
+{
+    exlist s;
+    RESERVE(s,seq.size());
+
+    if (level==1) {
+        return seq;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    --level;
+    for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).eval(level));
+    }
+    return s;
+}
+
+exlist lst::evalfchildren(int level) const
+{
+    exlist s;
+    RESERVE(s,seq.size());
+
+    if (level==1) {
+        return seq;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    --level;
+    for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).evalf(level));
+    }
+    return s;
+}
+
+exlist lst::normalchildren(int level) const
+{
+    exlist s;
+    RESERVE(s,seq.size());
+
+    if (level==1) {
+        return seq;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    --level;
+    for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).normal(level));
+    }
+    return s;
+}
+
+exlist lst::diffchildren(symbol const & y) const
+{
+    exlist s;
+    RESERVE(s,seq.size());
+    for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).diff(y));
+    }
+    return s;
+}
+
+/* obsolete subschildren
+exlist lst::subschildren(lst const & ls, lst const & lr) const
+{
+    exlist s;
+    RESERVE(s,seq.size());
+    for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).subs(ls,lr));
+    }
+    return s;
+}
+*/
+
+exlist * lst::subschildren(lst const & ls, lst const & lr) 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)
+
+    exlist::const_iterator last=seq.end();
+    exlist::const_iterator cit=seq.begin();
+    while (cit!=last) {
+        ex const & subsed_ex=(*cit).subs(ls,lr);
+        if (!are_ex_trivially_equal(*cit,subsed_ex)) {
+
+            // something changed, copy seq, subs and return it
+            exlist *s=new exlist;
+            RESERVE(*s,seq.size());
+
+            // copy parts of seq which are known not to have changed
+            exlist::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!=last) {
+                s->push_back((*cit2).subs(ls,lr));
+                ++cit2;
+           }
+            return s;
+        }
+        ++cit;
+    }
+    
+    return 0; // nothing has changed
+}
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned lst::precedence=10;
+
+//////////
+// global constants
+//////////
+
+const lst some_lst;
+type_info const & typeid_lst=typeid(some_lst);
+
diff --git a/ginac/lst.h b/ginac/lst.h
new file mode 100644 (file)
index 0000000..66af406
--- /dev/null
@@ -0,0 +1,116 @@
+/** @file lst.h
+ *
+ *  Definition of GiNaC's lst. 
+ *  This file was generated automatically by container.pl.
+ *  Please do not modify it directly, edit the perl script instead!
+ *  container.pl options: $CONTAINER=lst
+ *                        $STLHEADER=list
+ *                        $reserve=0
+ *                        $prepend=1
+ *                        $let_op=1
+ *                        $open_bracket=[
+ *                        $close_bracket=] */
+
+#ifndef _LST_H_
+#define _LST_H_
+
+#include <list>
+
+#include <ginac/ginac.h>
+
+typedef list<ex> exlist;
+
+class lst : public basic
+{
+
+public:
+    lst();
+    ~lst();
+    lst(lst const & other);
+    lst const & operator=(lst const & other);
+protected:
+    void copy(lst const & other);
+    void destroy(bool call_parent);
+
+public:
+    lst(exlist const & s, bool discardable=0);
+    lst(exlist * vp); // vp will be deleted
+    explicit lst(ex const & e1);
+    explicit lst(ex const & e1, ex const & e2);
+    explicit lst(ex const & e1, ex const & e2, ex const & e3);
+    explicit lst(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4);
+    explicit lst(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5);
+    explicit lst(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6);
+    explicit lst(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7);
+    explicit lst(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8);
+    explicit lst(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8, ex const & e9);
+    explicit lst(ex const & e1, ex const & e2, ex const & e3,
+             ex const & e4, ex const & e5, ex const & e6,
+             ex const & e7, ex const & e8, ex const & e9,
+             ex const &e10);
+
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printtree(ostream & os, unsigned indent) const;
+    bool info(unsigned inf) const;
+    int nops() const;
+    ex & let_op(int const i);
+    ex expand(unsigned options=0) const;
+    bool has(ex const & 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(symbol const & s) const;
+    ex subs(lst const & ls, lst const & lr) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+
+    // new virtual functions which can be overridden by derived classes
+public:
+    virtual lst & append(ex const & b);
+    virtual lst & prepend(ex const & b);
+
+protected:
+    virtual void printseq(ostream & os, char openbracket, char delim,
+                          char closebracket, unsigned this_precedence,
+                          unsigned upper_precedence=0) const;
+    virtual ex thislst(exlist const & v) const;
+    virtual ex thislst(exlist * vp) const;
+
+protected:
+    bool is_canonical() const;
+    exlist evalchildren(int level) const;
+    exlist evalfchildren(int level) const;
+    exlist normalchildren(int level) const;
+    exlist diffchildren(symbol const & s) const;
+    exlist * subschildren(lst const & ls, lst const & lr) const;
+
+protected:
+    exlist seq;
+    static unsigned precedence;
+};
+
+// global constants
+
+extern const lst some_lst;
+extern type_info const & typeid_lst;
+
+// macros
+
+#define ex_to_lst(X) (static_cast<lst const &>(*(X).bp))
+
+#endif // ndef _LST_H_
+
diff --git a/ginac/lst_suppl.cpp b/ginac/lst_suppl.cpp
new file mode 100644 (file)
index 0000000..6280169
--- /dev/null
@@ -0,0 +1,14 @@
+/** @file lst_suppl.cpp
+ *
+ *  Supplement to lst.cpp, contains the parts which were
+ *  not automatically generated. */
+
+#include "ginac.h"
+
+bool lst::info(unsigned inf) const
+{
+    if (inf==info_flags::list) return 1;
+    return basic::info(inf);
+}
+
+
diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp
new file mode 100644 (file)
index 0000000..edf2a94
--- /dev/null
@@ -0,0 +1,852 @@
+/** @file matrix.cpp
+ *
+ *  Implementation of symbolic matrices */
+
+#include <algorithm>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor, assignment operator
+// and helpers:
+//////////
+
+// public
+
+/** Default ctor.  Initializes to 1 x 1-dimensional zero-matrix. */
+matrix::matrix()
+    : basic(TINFO_MATRIX), row(1), col(1)
+{
+    debugmsg("matrix default constructor",LOGLEVEL_CONSTRUCT);
+    m.push_back(exZERO());
+}
+
+matrix::~matrix()
+{
+    debugmsg("matrix destructor",LOGLEVEL_DESTRUCT);
+}
+
+matrix::matrix(matrix const & other)
+{
+    debugmsg("matrix copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+matrix const & matrix::operator=(matrix const & other)
+{
+    debugmsg("matrix operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void matrix::copy(matrix const & other)
+{
+    basic::copy(other);
+    row=other.row;
+    col=other.col;
+    m=other.m;  // use STL's vector copying
+}
+
+void matrix::destroy(bool call_parent)
+{
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+/** Very common ctor.  Initializes to r x c-dimensional zero-matrix.
+ *
+ *  @param r number of rows
+ *  @param c number of cols */
+matrix::matrix(int r, int c)
+    : basic(TINFO_MATRIX), row(r), col(c)
+{
+    debugmsg("matrix constructor from int,int",LOGLEVEL_CONSTRUCT);
+    m.resize(r*c, exZERO());
+}
+
+// protected
+
+/** Ctor from representation, for internal use only. */
+matrix::matrix(int r, int c, vector<ex> const & m2)
+    : basic(TINFO_MATRIX), row(r), col(c), m(m2)
+{
+    debugmsg("matrix constructor from int,int,vector<ex>",LOGLEVEL_CONSTRUCT);
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * matrix::duplicate() const
+{
+    debugmsg("matrix duplicate",LOGLEVEL_DUPLICATE);
+    return new matrix(*this);
+}
+
+/** nops is defined to be rows x columns. */
+int matrix::nops() const
+{
+    return row*col;
+}
+
+/** returns matrix entry at position (i/col, i%col). */
+ex & matrix::let_op(int const i)
+{
+    return m[i];
+}
+
+/** expands the elements of a matrix entry by entry. */
+ex matrix::expand(unsigned options) const
+{
+    vector<ex> tmp(row*col);
+    for (int i=0; i<row*col; ++i) {
+        tmp[i]=m[i].expand(options);
+    }
+    return matrix(row, col, tmp);
+}
+
+/** Search ocurrences.  A matrix 'has' an expression if it is the expression
+ *  itself or one of the elements 'has' it. */
+bool matrix::has(ex const & other) const
+{
+    ASSERT(other.bp!=0);
+    
+    // tautology: it is the expression itself
+    if (is_equal(*other.bp)) return true;
+    
+    // search all the elements
+    for (vector<ex>::const_iterator r=m.begin(); r!=m.end(); ++r) {
+        if ((*r).has(other)) return true;
+    }
+    return false;
+}
+
+/** evaluate matrix entry by entry. */
+ex matrix::eval(int level) const
+{
+    debugmsg("matrix eval",LOGLEVEL_MEMBER_FUNCTION);
+    
+    // check if we have to do anything at all
+    if ((level==1)&&(flags & status_flags::evaluated)) {
+        return *this;
+    }
+    
+    // emergency break
+    if (level == -max_recursion_level) {
+        throw (std::runtime_error("matrix::eval(): recursion limit exceeded"));
+    }
+    
+    // eval() entry by entry
+    vector<ex> m2(row*col);
+    --level;    
+    for (int r=0; r<row; ++r) {
+        for (int c=0; c<col; ++c) {
+            m2[r*col+c] = m[r*col+c].eval(level);
+        }
+    }
+    
+    return (new matrix(row, col, m2))->setflag(status_flags::dynallocated |
+                                               status_flags::evaluated );
+}
+
+/** evaluate matrix numerically entry by entry. */
+ex matrix::evalf(int level) const
+{
+    debugmsg("matrix evalf",LOGLEVEL_MEMBER_FUNCTION);
+        
+    // check if we have to do anything at all
+    if (level==1) {
+        return *this;
+    }
+    
+    // emergency break
+    if (level == -max_recursion_level) {
+        throw (std::runtime_error("matrix::evalf(): recursion limit exceeded"));
+    }
+    
+    // evalf() entry by entry
+    vector<ex> m2(row*col);
+    --level;
+    for (int r=0; r<row; ++r) {
+        for (int c=0; c<col; ++c) {
+            m2[r*col+c] = m[r*col+c].evalf(level);
+        }
+    }
+    return matrix(row, col, m2);
+}
+
+// protected
+
+int matrix::compare_same_type(basic const & other) const
+{
+    ASSERT(is_exactly_of_type(other, matrix));
+    matrix const & o=static_cast<matrix &>(const_cast<basic &>(other));
+    
+    // compare number of rows
+    if (row != o.rows()) {
+        return row < o.rows() ? -1 : 1;
+    }
+    
+    // compare number of columns
+    if (col != o.cols()) {
+        return col < o.cols() ? -1 : 1;
+    }
+    
+    // equal number of rows and columns, compare individual elements
+    int cmpval;
+    for (int r=0; r<row; ++r) {
+        for (int c=0; c<col; ++c) {
+            cmpval=((*this)(r,c)).compare(o(r,c));
+            if (cmpval!=0) return cmpval;
+        }
+    }
+    // all elements are equal => matrices are equal;
+    return 0;
+}
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+
+/** Sum of matrices.
+ *
+ *  @exception logic_error (incompatible matrices) */
+matrix matrix::add(matrix const & other) const
+{
+    if (col != other.col || row != other.row) {
+        throw (std::logic_error("matrix::add(): incompatible matrices"));
+    }
+    
+    vector<ex> sum(this->m);
+    vector<ex>::iterator i;
+    vector<ex>::const_iterator ci;
+    for (i=sum.begin(), ci=other.m.begin();
+         i!=sum.end();
+         ++i, ++ci) {
+        (*i) += (*ci);
+    }
+    return matrix(row,col,sum);
+}
+
+/** Difference of matrices.
+ *
+ *  @exception logic_error (incompatible matrices) */
+matrix matrix::sub(matrix const & other) const
+{
+    if (col != other.col || row != other.row) {
+        throw (std::logic_error("matrix::sub(): incompatible matrices"));
+    }
+    
+    vector<ex> dif(this->m);
+    vector<ex>::iterator i;
+    vector<ex>::const_iterator ci;
+    for (i=dif.begin(), ci=other.m.begin();
+         i!=dif.end();
+         ++i, ++ci) {
+        (*i) -= (*ci);
+    }
+    return matrix(row,col,dif);
+}
+
+/** Product of matrices.
+ *
+ *  @exception logic_error (incompatible matrices) */
+matrix matrix::mul(matrix const & other) const
+{
+    if (col != other.row) {
+        throw (std::logic_error("matrix::mul(): incompatible matrices"));
+    }
+    
+    vector<ex> prod(row*other.col);
+    for (int i=0; i<row; ++i) {
+        for (int j=0; j<other.col; ++j) {
+            for (int l=0; l<col; ++l) {
+                prod[i*other.col+j] += m[i*col+l] * other.m[l*other.col+j];
+            }
+        }
+    }
+    return matrix(row, other.col, prod);
+}
+
+/** operator() to access elements.
+ *
+ *  @param ro row of element
+ *  @param co column of element 
+ *  @exception range_error (index out of range) */
+ex const & matrix::operator() (int ro, int co) const
+{
+    if (ro<0 || ro>=row || co<0 || co>=col) {
+        throw (std::range_error("matrix::operator(): index out of range"));
+    }
+    
+    return m[ro*col+co];
+}
+
+/** Set individual elements manually.
+ *
+ *  @exception range_error (index out of range) */
+matrix & matrix::set(int ro, int co, ex value)
+{
+    if (ro<0 || ro>=row || co<0 || co>=col) {
+        throw (std::range_error("matrix::set(): index out of range"));
+    }
+    
+    ensure_if_modifiable();
+    m[ro*col+co]=value;
+    return *this;
+}
+
+/** Transposed of an m x n matrix, producing a new n x m matrix object that
+ *  represents the transposed. */
+matrix matrix::transpose(void) const
+{
+    vector<ex> trans(col*row);
+    
+    for (int r=0; r<col; ++r) {
+        for (int c=0; c<row; ++c) {
+            trans[r*row+c] = m[c*col+r];
+        }
+    }
+    return matrix(col,row,trans);
+}
+
+/* Determiant of purely numeric matrix, using pivoting. This routine is only
+ * called internally by matrix::determinant(). */
+ex determinant_numeric(const matrix & M)
+{
+    ASSERT(M.rows()==M.cols());  // cannot happen, just in case...
+    matrix tmp(M);
+    ex det=exONE();
+    ex piv;
+    
+    for (int r1=0; r1<M.rows(); ++r1) {
+        int indx = tmp.pivot(r1);
+        if (indx == -1) {
+            return exZERO();
+        }
+        if (indx != 0) {
+            det *= exMINUSONE();
+        }
+        det = det * tmp.m[r1*M.cols()+r1];
+        for (int r2=r1+1; r2<M.rows(); ++r2) {
+            piv = tmp.m[r2*M.cols()+r1] / tmp.m[r1*M.cols()+r1];
+            for (int c=r1+1; c<M.cols(); c++) {
+                tmp.m[r2*M.cols()+c] -= piv * tmp.m[r1*M.cols()+c];
+            }
+        }
+    }
+    return det;
+}
+
+// Compute the sign of a permutation of a vector of things, used internally
+// by determinant_symbolic_perm() where it is instantiated for int.
+template <class T>
+int permutation_sign(vector<T> s)
+{
+    if (s.size() < 2)
+        return 0;
+    int sigma=1;
+    for (typename vector<T>::iterator i=s.begin(); i!=s.end()-1; ++i) {
+        for (typename vector<T>::iterator j=i+1; j!=s.end(); ++j) {
+            if (*i == *j)
+                return 0;
+            if (*i > *j) {
+                iter_swap(i,j);
+                sigma = -sigma;
+            }
+        }
+    }
+    return sigma;
+}
+
+/** Determinant built by application of the full permutation group. This
+ *  routine is only called internally by matrix::determinant(). */
+ex determinant_symbolic_perm(const matrix & M)
+{
+    ASSERT(M.rows()==M.cols());  // cannot happen, just in case...
+    
+    if (M.rows()==1) {  // speed things up
+        return M(0,0);
+    }
+    
+    ex det;
+    ex term;
+    vector<int> sigma(M.cols());
+    for (int i=0; i<M.cols(); ++i) sigma[i]=i;
+    
+    do {
+        term = M(sigma[0],0);
+        for (int i=1; i<M.cols(); ++i) term *= M(sigma[i],i);
+        det += permutation_sign(sigma)*term;
+    } while (next_permutation(sigma.begin(), sigma.end()));
+    
+    return det;
+}
+
+/** Recursive determiant for small matrices having at least one symbolic entry.
+ *  This algorithm is also known as Laplace-expansion. This routine is only
+ *  called internally by matrix::determinant(). */
+ex determinant_symbolic_minor(const matrix & M)
+{
+    ASSERT(M.rows()==M.cols());  // cannot happen, just in case...
+    
+    if (M.rows()==1) {  // end of recursion
+        return M(0,0);
+    }
+    if (M.rows()==2) {  // speed things up
+        return (M(0,0)*M(1,1)-
+                M(1,0)*M(0,1));
+    }
+    if (M.rows()==3) {  // speed things up even a little more
+        return ((M(2,1)*M(0,2)-M(2,2)*M(0,1))*M(1,0)+
+                (M(1,2)*M(0,1)-M(1,1)*M(0,2))*M(2,0)+
+                (M(2,2)*M(1,1)-M(2,1)*M(1,2))*M(0,0));
+    }
+    
+    ex det;
+    matrix minorM(M.rows()-1,M.cols()-1);
+    for (int r1=0; r1<M.rows(); ++r1) {
+        // assemble the minor matrix
+        for (int r=0; r<minorM.rows(); ++r) {
+            for (int c=0; c<minorM.cols(); ++c) {
+                if (r<r1) {
+                    minorM.set(r,c,M(r,c+1));
+                } else {
+                    minorM.set(r,c,M(r+1,c+1));
+                }
+            }
+        }
+        // recurse down
+        if (r1%2) {
+            det -= M(r1,0) * determinant_symbolic_minor(minorM);
+        } else {
+            det += M(r1,0) * determinant_symbolic_minor(minorM);
+        }
+    }
+    return det;
+}
+
+/*  Leverrier algorithm for large matrices having at least one symbolic entry.
+ *  This routine is only called internally by matrix::determinant(). The
+ *  algorithm is deemed bad for symbolic matrices since it returns expressions
+ *  that are very hard to canonicalize. */
+/*ex determinant_symbolic_leverrier(const matrix & M)
+ *{
+ *    ASSERT(M.rows()==M.cols());  // cannot happen, just in case...
+ *    
+ *    matrix B(M);
+ *    matrix I(M.row, M.col);
+ *    ex c=B.trace();
+ *    for (int i=1; i<M.row; ++i) {
+ *        for (int j=0; j<M.row; ++j)
+ *            I.m[j*M.col+j] = c;
+ *        B = M.mul(B.sub(I));
+ *        c = B.trace()/ex(i+1);
+ *    }
+ *    if (M.row%2) {
+ *        return c;
+ *    } else {
+ *        return -c;
+ *    }
+ *}*/
+
+/** Determinant of square matrix.  This routine doesn't actually calculate the
+ *  determinant, it only implements some heuristics about which algorithm to
+ *  call.  When the parameter for normalization is explicitly turned off this
+ *  method does not normalize its result at the end, which might imply that
+ *  the symbolic 2x2 matrix [[a/(a-b),1],[b/(a-b),1]] is not immediatly
+ *  recognized to be unity.  (This is Mathematica's default behaviour, it
+ *  should be used with care.)
+ *
+ *  @param     normalized may be set to false if no normalization of the
+ *             result is desired (i.e. to force Mathematica behavior, Maple
+ *             does normalize the result).
+ *  @return    the determinant as a new expression
+ *  @exception logic_error (matrix not square) */
+ex matrix::determinant(bool normalized) const
+{
+    if (row != col) {
+        throw (std::logic_error("matrix::determinant(): matrix not square"));
+    }
+
+    // check, if there are non-numeric entries in the matrix:
+    for (vector<ex>::const_iterator r=m.begin(); r!=m.end(); ++r) {
+        if (!(*r).info(info_flags::numeric)) {
+            if (normalized) {
+                return determinant_symbolic_minor(*this).normal();
+            } else {
+                return determinant_symbolic_perm(*this);
+            }
+        }
+    }
+    // if it turns out that all elements are numeric
+    return determinant_numeric(*this);
+}
+
+/** Trace of a matrix.
+ *
+ *  @return    the sum of diagonal elements
+ *  @exception logic_error (matrix not square) */
+ex matrix::trace(void) const
+{
+    if (row != col) {
+        throw (std::logic_error("matrix::trace(): matrix not square"));
+    }
+    
+    ex tr;
+    for (int r=0; r<col; ++r) {
+        tr += m[r*col+r];
+    }
+    return tr;
+}
+
+/** Characteristic Polynomial.  The characteristic polynomial of a matrix M is
+ *  defined as the determiant of (M - lambda * 1) where 1 stands for the unit
+ *  matrix of the same dimension as M.  This method returns the characteristic
+ *  polynomial as a new expression.
+ *
+ *  @return    characteristic polynomial as new expression
+ *  @exception logic_error (matrix not square)
+ *  @see       matrix::determinant() */
+ex matrix::charpoly(ex const & lambda) const
+{
+    if (row != col) {
+        throw (std::logic_error("matrix::charpoly(): matrix not square"));
+    }
+    
+    matrix M(*this);
+    for (int r=0; r<col; ++r) {
+        M.m[r*col+r] -= lambda;
+    }
+    return (M.determinant());
+}
+
+/** Inverse of this matrix.
+ *
+ *  @return    the inverted matrix
+ *  @exception logic_error (matrix not square)
+ *  @exception runtime_error (singular matrix) */
+matrix matrix::inverse(void) const
+{
+    if (row != col) {
+        throw (std::logic_error("matrix::inverse(): matrix not square"));
+    }
+    
+    matrix tmp(row,col);
+    // set tmp to the unit matrix
+    for (int i=0; i<col; ++i) {
+        tmp.m[i*col+i] = exONE();
+    }
+    // create a copy of this matrix
+    matrix cpy(*this);
+    for (int r1=0; r1<row; ++r1) {
+        int indx = cpy.pivot(r1);
+        if (indx == -1) {
+            throw (std::runtime_error("matrix::inverse(): singular matrix"));
+        }
+        if (indx != 0) {  // swap rows r and indx of matrix tmp
+            for (int i=0; i<col; ++i) {
+                tmp.m[r1*col+i].swap(tmp.m[indx*col+i]);
+            }
+        }
+        ex a1 = cpy.m[r1*col+r1];
+        for (int c=0; c<col; ++c) {
+            cpy.m[r1*col+c] /= a1;
+            tmp.m[r1*col+c] /= a1;
+        }
+        for (int r2=0; r2<row; ++r2) {
+            if (r2 != r1) {
+                ex a2 = cpy.m[r2*col+r1];
+                for (int c=0; c<col; ++c) {
+                    cpy.m[r2*col+c] -= a2 * cpy.m[r1*col+c];
+                    tmp.m[r2*col+c] -= a2 * tmp.m[r1*col+c];
+                }
+            }
+        }
+    }
+    return tmp;
+}
+
+void matrix::ffe_swap(int r1, int c1, int r2 ,int c2)
+{
+    ensure_if_modifiable();
+    
+    ex tmp=ffe_get(r1,c1);
+    ffe_set(r1,c1,ffe_get(r2,c2));
+    ffe_set(r2,c2,tmp);
+}
+
+void matrix::ffe_set(int r, int c, ex e)
+{
+    set(r-1,c-1,e);
+}
+
+ex matrix::ffe_get(int r, int c) const
+{
+    return operator()(r-1,c-1);
+}
+
+/** Solve a set of equations for an m x n matrix by fraction-free Gaussian
+ *  elimination. Based on algorithm 9.1 from 'Algorithms for Computer Algebra'
+ *  by Keith O. Geddes et al.
+ *
+ *  @param vars n x p matrix
+ *  @param rhs m x p matrix
+ *  @exception logic_error (incompatible matrices)
+ *  @exception runtime_error (singular matrix) */
+matrix matrix::fraction_free_elim(matrix const & vars,
+                                  matrix const & rhs) const
+{
+    if ((row != rhs.row) || (col != vars.row) || (rhs.col != vars.col)) {
+        throw (std::logic_error("matrix::solve(): incompatible matrices"));
+    }
+    
+    matrix a(*this); // make a copy of the matrix
+    matrix b(rhs);     // make a copy of the rhs vector
+    
+    // given an m x n matrix a, reduce it to upper echelon form
+    int m=a.row;
+    int n=a.col;
+    int sign=1;
+    ex divisor=1;
+    int r=1;
+    
+    // eliminate below row r, with pivot in column k
+    for (int k=1; (k<=n)&&(r<=m); ++k) {
+        // find a nonzero pivot
+        int p;
+        for (p=r; (p<=m)&&(a.ffe_get(p,k).is_equal(exZERO())); ++p) {}
+        // pivot is in row p
+        if (p<=m) {
+            if (p!=r) {
+                // switch rows p and r
+                for (int j=k; j<=n; ++j) {
+                    a.ffe_swap(p,j,r,j);
+                }
+                b.ffe_swap(p,1,r,1);
+                // keep track of sign changes due to row exchange
+                sign=-sign;
+            }
+            for (int i=r+1; i<=m; ++i) {
+                for (int j=k+1; j<=n; ++j) {
+                    a.ffe_set(i,j,(a.ffe_get(r,k)*a.ffe_get(i,j)
+                                  -a.ffe_get(r,j)*a.ffe_get(i,k))/divisor);
+                    a.ffe_set(i,j,a.ffe_get(i,j).normal() /*.normal() */ );
+                }
+                b.ffe_set(i,1,(a.ffe_get(r,k)*b.ffe_get(i,1)
+                              -b.ffe_get(r,1)*a.ffe_get(i,k))/divisor);
+                b.ffe_set(i,1,b.ffe_get(i,1).normal() /*.normal() */ );
+                a.ffe_set(i,k,0);
+            }
+            divisor=a.ffe_get(r,k);
+            r++;
+        }
+    }
+    // optionally compute the determinant for square or augmented matrices
+    // if (r==m+1) { det=sign*divisor; } else { det=0; }
+    
+    /*
+    for (int r=1; r<=m; ++r) {
+        for (int c=1; c<=n; ++c) {
+            cout << a.ffe_get(r,c) << "\t";
+        }
+        cout << " | " <<  b.ffe_get(r,1) << endl;
+    }
+    */
+    
+#ifdef DOASSERT
+    // test if we really have an upper echelon matrix
+    int zero_in_last_row=-1;
+    for (int r=1; r<=m; ++r) {
+        int zero_in_this_row=0;
+        for (int c=1; c<=n; ++c) {
+            if (a.ffe_get(r,c).is_equal(exZERO())) {
+               zero_in_this_row++;
+            } else {
+                break;
+            }
+        }
+        ASSERT((zero_in_this_row>zero_in_last_row)||(zero_in_this_row=n));
+        zero_in_last_row=zero_in_this_row;
+    }
+#endif // def DOASSERT
+    
+    // assemble solution
+    matrix sol(n,1);
+    int last_assigned_sol=n+1;
+    for (int r=m; r>0; --r) {
+        int first_non_zero=1;
+        while ((first_non_zero<=n)&&(a.ffe_get(r,first_non_zero).is_zero())) {
+            first_non_zero++;
+        }
+        if (first_non_zero>n) {
+            // row consists only of zeroes, corresponding rhs must be 0 as well
+            if (!b.ffe_get(r,1).is_zero()) {
+                throw (std::runtime_error("matrix::fraction_free_elim(): singular matrix"));
+            }
+        } else {
+            // assign solutions for vars between first_non_zero+1 and
+            // last_assigned_sol-1: free parameters
+            for (int c=first_non_zero+1; c<=last_assigned_sol-1; ++c) {
+                sol.ffe_set(c,1,vars.ffe_get(c,1));
+            }
+            ex e=b.ffe_get(r,1);
+            for (int c=first_non_zero+1; c<=n; ++c) {
+                e=e-a.ffe_get(r,c)*sol.ffe_get(c,1);
+            }
+            sol.ffe_set(first_non_zero,1,
+                        (e/a.ffe_get(r,first_non_zero)).normal());
+            last_assigned_sol=first_non_zero;
+        }
+    }
+    // assign solutions for vars between 1 and
+    // last_assigned_sol-1: free parameters
+    for (int c=1; c<=last_assigned_sol-1; ++c) {
+        sol.ffe_set(c,1,vars.ffe_get(c,1));
+    }
+
+    /*
+    for (int c=1; c<=n; ++c) {
+        cout << vars.ffe_get(c,1) << "->" << sol.ffe_get(c,1) << endl;
+    }
+    */
+    
+#ifdef DOASSERT
+    // test solution with echelon matrix
+    for (int r=1; r<=m; ++r) {
+        ex e=0;
+        for (int c=1; c<=n; ++c) {
+            e=e+a.ffe_get(r,c)*sol.ffe_get(c,1);
+        }
+        if (!(e-b.ffe_get(r,1)).normal().is_zero()) {
+            cout << "e=" << e;
+            cout << "b.ffe_get(" << r<<",1)=" << b.ffe_get(r,1) << endl;
+            cout << "diff=" << (e-b.ffe_get(r,1)).normal() << endl;
+        }
+        ASSERT((e-b.ffe_get(r,1)).normal().is_zero());
+    }
+
+    // test solution with original matrix
+    for (int r=1; r<=m; ++r) {
+        ex e=0;
+        for (int c=1; c<=n; ++c) {
+            e=e+ffe_get(r,c)*sol.ffe_get(c,1);
+        }
+        try {
+        if (!(e-rhs.ffe_get(r,1)).normal().is_zero()) {
+            cout << "e=" << e << endl;
+            e.printtree(cout);
+            ex en=e.normal();
+            cout << "e.normal()=" << en << endl;
+            en.printtree(cout);
+            cout << "rhs.ffe_get(" << r<<",1)=" << rhs.ffe_get(r,1) << endl;
+            cout << "diff=" << (e-rhs.ffe_get(r,1)).normal() << endl;
+        }
+        } catch (...) {
+            ex xxx=e-rhs.ffe_get(r,1);
+            cerr << "xxx=" << xxx << endl << endl;
+        }
+        ASSERT((e-rhs.ffe_get(r,1)).normal().is_zero());
+    }
+#endif // def DOASSERT
+    
+    return sol;
+}   
+    
+/** Solve simultaneous set of equations. */
+matrix matrix::solve(matrix const & v) const
+{
+    if (!(row == col && col == v.row)) {
+        throw (std::logic_error("matrix::solve(): incompatible matrices"));
+    }
+    
+    // build the extended matrix of *this with v attached to the right
+    matrix tmp(row,col+v.col);
+    for (int r=0; r<row; ++r) {
+        for (int c=0; c<col; ++c) {
+            tmp.m[r*tmp.col+c] = m[r*col+c];
+        }
+        for (int c=0; c<v.col; ++c) {
+            tmp.m[r*tmp.col+c+col] = v.m[r*v.col+c];
+        }
+    }
+    for (int r1=0; r1<row; ++r1) {
+        int indx = tmp.pivot(r1);
+        if (indx == -1) {
+            throw (std::runtime_error("matrix::solve(): singular matrix"));
+        }
+        for (int c=r1; c<tmp.col; ++c) {
+            tmp.m[r1*tmp.col+c] /= tmp.m[r1*tmp.col+r1];
+        }
+        for (int r2=r1+1; r2<row; ++r2) {
+            for (int c=r1; c<tmp.col; ++c) {
+                tmp.m[r2*tmp.col+c]
+                    -= tmp.m[r2*tmp.col+r1] * tmp.m[r1*tmp.col+c];
+            }
+        }
+    }
+    
+    // assemble the solution matrix
+    vector<ex> sol(v.row*v.col);
+    for (int c=0; c<v.col; ++c) {
+        for (int r=col-1; r>=0; --r) {
+            sol[r*v.col+c] = tmp[r*tmp.col+c];
+            for (int i=r+1; i<col; ++i) {
+                sol[r*v.col+c]
+                    -= tmp[r*tmp.col+i] * sol[i*v.col+c];
+            }
+        }
+    }
+    return matrix(v.row, v.col, sol);
+}
+
+// protected
+
+/** Partial pivoting method.
+ *  Usual pivoting returns the index to the element with the largest absolute
+ *  value and swaps the current row with the one where the element was found.
+ *  Here it does the same with the first non-zero element. (This works fine,
+ *  but may be far from optimal for numerics.) */
+int matrix::pivot(int ro)
+{
+    int k=ro;
+    
+    for (int r=ro; r<row; ++r) {
+        if (!m[r*col+ro].is_zero()) {
+            k = r;
+            break;
+        }
+    }
+    if (m[k*col+ro].is_zero()) {
+        return -1;
+    }
+    if (k!=ro) {  // swap rows
+        for (int c=0; c<col; ++c) {
+            m[k*col+c].swap(m[ro*col+c]);
+        }
+        return k;
+    }
+    return 0;
+}
+
+//////////
+// global constants
+//////////
+
+const matrix some_matrix;
+type_info const & typeid_matrix=typeid(some_matrix);
diff --git a/ginac/matrix.h b/ginac/matrix.h
new file mode 100644 (file)
index 0000000..66e89aa
--- /dev/null
@@ -0,0 +1,133 @@
+/** @file matrix.h
+ *
+ *  Interface to symbolic matrices */
+
+#ifndef _MATRIX_H_
+#define _MATRIX_H_
+
+#include "basic.h"
+#include "ex.h"
+#include <vector>
+
+/** Symbolic matrices. */
+class matrix : public basic
+{
+// friends
+    friend ex determinant_numeric(const matrix & m);
+    friend ex determinant_symbolic_perm(const matrix & m);
+    friend ex determinant_symbolic_minor(const matrix & m);
+// member functions
+
+    // default constructor, destructor, copy constructor, assignment operator
+    // and helpers:
+public:
+    matrix();
+    ~matrix();
+    matrix(matrix const & other);
+    matrix const & operator=(matrix const & other);
+protected:
+    void copy(matrix const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    matrix(int r, int c);
+    matrix(int r, int c, vector<ex> const & m2);
+   
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    int nops() const;
+    ex & let_op(int const i);
+    ex expand(unsigned options=0) const;
+    bool has(ex const & other) const;
+    ex eval(int level=0) const;
+    ex evalf(int level=0) const;
+    // ex subs(lst const & ls, lst const & lr) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    unsigned return_type(void) const { return return_types::noncommutative; };
+    // new virtual functions which can be overridden by derived classes
+    // (none)
+    
+    // non-virtual functions in this class
+public:
+    int rows() const            //! get number of rows.
+        { return row; }
+    int cols() const            //! get number of columns.
+        { return col; }
+    matrix add(matrix const & other) const;
+    matrix sub(matrix const & other) const;
+    matrix mul(matrix const & other) const;
+    ex const & operator() (int ro, int co) const;
+    matrix & set(int ro, int co, ex value);
+    matrix transpose(void) const;
+    ex determinant(bool normalized=true) const;
+    ex trace(void) const;
+    ex charpoly(ex const & lambda) const;
+    matrix inverse(void) const;
+    matrix fraction_free_elim(matrix const & vars, matrix const & v) const;
+    matrix solve(matrix const & v) const;
+protected:
+    int pivot(int ro);
+    void ffe_swap(int r1, int c1, int r2 ,int c2);
+    void ffe_set(int r, int c, ex e);
+    ex ffe_get(int r, int c) const;
+    
+// member variables
+protected:
+    int row;                    /**< number of rows      */
+    int col;                    /**< number of columns   */
+    vector<ex> m;               /**< representation (cols indexed first) */
+    static unsigned precedence;
+};
+
+// global constants
+extern const matrix some_matrix;
+extern type_info const & typeid_matrix;
+
+// wrapper functions around member functions
+
+inline int nops(matrix const & m)
+{ return m.nops(); }
+
+inline ex expand(matrix const & m, unsigned options=0)
+{ return m.expand(options); }
+
+inline bool has(matrix const & m, ex const & other)
+{ return m.has(other); }
+
+inline ex eval(matrix const & m, int level=0)
+{ return m.eval(level); }
+
+inline ex evalf(matrix const & m, int level=0)
+{ return m.evalf(level); }
+
+inline int rows(matrix const & m)
+{ return m.rows(); }
+
+inline int cols(matrix const & m)
+{ return m.cols(); }
+
+inline matrix transpose(matrix const & m)
+{ return m.transpose(); }
+
+inline ex determinant(matrix const & m, bool normalized=true)
+{ return m.determinant(normalized); }
+
+inline ex trace(matrix const & m)
+{ return m.trace(); }
+
+inline ex charpoly(matrix const & m, ex const & lambda)
+{ return m.charpoly(lambda); }
+
+inline matrix inverse(matrix const & m)
+{ return m.inverse(); }
+
+// macros
+
+#define ex_to_matrix(X) (static_cast<matrix const &>(*(X).bp))
+
+#endif // ndef _MATRIX_H_
diff --git a/ginac/mul.cpp b/ginac/mul.cpp
new file mode 100644 (file)
index 0000000..bf5e70d
--- /dev/null
@@ -0,0 +1,994 @@
+/** @file mul.cpp
+ *
+ *  Implementation of GiNaC's products of expressions. */
+
+#include <vector>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+mul::mul()
+{
+    debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_MUL;
+}
+
+mul::~mul()
+{
+    debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+mul::mul(mul const & other)
+{
+    debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+mul const & mul::operator=(mul const & other)
+{
+    debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void mul::copy(mul const & other)
+{
+    expairseq::copy(other);
+}
+
+void mul::destroy(bool call_parent)
+{
+    if (call_parent) expairseq::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+mul::mul(ex const & lh, ex const & rh)
+{
+    debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_MUL;
+    overall_coeff=exONE();
+    construct_from_2_ex(lh,rh);
+    ASSERT(is_canonical());
+}
+
+mul::mul(exvector const & v)
+{
+    debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_MUL;
+    overall_coeff=exONE();
+    construct_from_exvector(v);
+    ASSERT(is_canonical());
+}
+
+/*
+mul::mul(epvector const & v, bool do_not_canonicalize)
+{
+    debugmsg("mul constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_MUL;
+    if (do_not_canonicalize) {
+        seq=v;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+        combine_same_terms(); // to build hashtab
+#endif // def EXPAIRSEQ_USE_HASHTAB
+    } else {
+        construct_from_epvector(v);
+    }
+    ASSERT(is_canonical());
+}
+*/
+
+mul::mul(epvector const & v)
+{
+    debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_MUL;
+    overall_coeff=exONE();
+    construct_from_epvector(v);
+    ASSERT(is_canonical());
+}
+
+mul::mul(epvector const & v, ex const & oc)
+{
+    debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_MUL;
+    overall_coeff=oc;
+    construct_from_epvector(v);
+    ASSERT(is_canonical());
+}
+
+mul::mul(epvector * vp, ex const & oc)
+{
+    debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_MUL;
+    ASSERT(vp!=0);
+    overall_coeff=oc;
+    construct_from_epvector(*vp);
+    delete vp;
+    ASSERT(is_canonical());
+}
+
+mul::mul(ex const & lh, ex const & mh, ex const & rh)
+{
+    debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_MUL;
+    exvector factors;
+    factors.reserve(3);
+    factors.push_back(lh);
+    factors.push_back(mh);
+    factors.push_back(rh);
+    overall_coeff=exONE();
+    construct_from_exvector(factors);
+    ASSERT(is_canonical());
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * mul::duplicate() const
+{
+    debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
+    return new mul(*this);
+}
+
+bool mul::info(unsigned inf) const
+{
+    // TODO: optimize
+    if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
+        for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+            if (!(recombine_pair_to_ex(*it).info(inf)))
+                return false;
+        }
+        return true;
+    } else {
+        return expairseq::info(inf);
+    }
+}
+
+typedef vector<int> intvector;
+
+int mul::degree(symbol const & s) const
+{
+    int deg_sum=0;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
+    }
+    return deg_sum;
+}
+
+int mul::ldegree(symbol const & s) const
+{
+    int deg_sum=0;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
+    }
+    return deg_sum;
+}
+
+ex mul::coeff(symbol const & s, int const n) const
+{
+    exvector coeffseq;
+    coeffseq.reserve(seq.size()+1);
+    
+    if (n==0) {
+        // product of individual coeffs
+        // if a non-zero power of s is found, the resulting product will be 0
+        epvector::const_iterator it=seq.begin();
+        while (it!=seq.end()) {
+            coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
+            ++it;
+        }
+        coeffseq.push_back(overall_coeff);
+        return (new mul(coeffseq))->setflag(status_flags::dynallocated);
+    }
+         
+    epvector::const_iterator it=seq.begin();
+    bool coeff_found=0;
+    while (it!=seq.end()) {
+        ex t=recombine_pair_to_ex(*it);
+        ex c=t.coeff(s,n);
+        if (!c.is_zero()) {
+            coeffseq.push_back(c);
+            coeff_found=1;
+        } else {
+            coeffseq.push_back(t);
+        }
+        ++it;
+    }
+    if (coeff_found) {
+        coeffseq.push_back(overall_coeff);
+        return (new mul(coeffseq))->setflag(status_flags::dynallocated);
+    }
+    
+    return exZERO();
+}
+
+/*
+ex mul::eval(int level) const
+{
+    // simplifications: *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric(), move pairs to end first)
+    //                  *(...,x,1) -> *(...,x)
+    //                  *(...,x,0) -> 0
+    //                  *(+(x,y,...),(c,1)) -> *(+(*(x,c),*(y,c),...)) (c numeric())
+    //                  *(x) -> x
+    //                  *() -> 1
+
+    debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
+
+    if ((level==1)&&(flags & status_flags::evaluated)) {
+#ifdef DOASSERT
+        for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+            ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
+                   (!(ex_to_numeric((*cit).coeff).is_integer())));
+        }
+
+        // test if all numerics were moved to the end and
+        // all numerics with coeff 1 to the very end
+        if (seq.size()!=0) {
+            epvector::const_iterator cit=seq.end();
+            bool all_coeff_1=true;
+            bool all_numeric=true;
+            do {
+                cit--;
+                if (is_ex_exactly_of_type((*cit).rest,numeric)) {
+                    ASSERT(all_numeric);
+                    if ((*cit).coeff.is_equal(exONE())) {
+                        ASSERT(all_coeff_1);
+                    } else {
+                        all_coeff_1=false;
+                    }
+                } else {
+                    all_numeric=false;
+                }
+            } while (cit!=seq.begin());
+        }
+#endif // def DOASSERT    
+        return *this;
+    }
+
+    epvector newseq;
+    epvector::iterator it1,it2;
+    bool seq_copied=false;
+
+    epvector * evaled_seqp=evalchildren(level);
+    if (evaled_seqp!=0) {
+        // do more evaluation later
+        return (new mul(evaled_seqp))->setflag(status_flags::dynallocated);
+    }
+
+    // combine pairs with coeff 1 (all numerics should be at end, assert below)
+    if (seq.size()>1) {
+        // count number of pairs with coeff 1
+        unsigned num_coeff_1=0;
+        bool still_numeric=true;
+        epvector::const_iterator cit=seq.end();
+        unsigned first_pos;
+        unsigned second_pos;
+        do {
+            cit--;
+            if (is_ex_exactly_of_type((*cit).rest,numeric)) {
+                if ((*cit).coeff.is_equal(exONE())) {
+                    num_coeff_1++;
+                }
+            } else {
+                still_numeric=false;
+            }
+        } while ((cit!=seq.begin())&&still_numeric);
+        if (num_coeff_1>1) {
+            newseq=seq;
+            
+    }
+    
+    
+#ifdef DOASSERT
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
+               (!(ex_to_numeric((*cit).coeff).is_integer())));
+    }
+
+    // test if all numerics were moved to the end and
+    // all numerics with coeff 1 to the very end
+    if (seq.size()!=0) {
+        epvector::const_iterator cit=seq.end();
+        bool all_coeff_1=true;
+        bool all_numeric=true;
+        do {
+            cit--;
+            if (is_ex_exactly_of_type((*cit).rest,numeric)) {
+                ASSERT(all_numeric);
+                if ((*cit).coeff.is_equal(exONE())) {
+                    ASSERT(all_coeff_1);
+                } else {
+                    all_coeff_1=false;
+                }
+            } else {
+                all_numeric=false;
+            }
+        } while (cit!=seq.begin());
+    }
+#endif // def DOASSERT
+    
+    if (flags & status_flags::evaluated) {
+        return *this;
+    }
+    
+    expair const & last_expair=*(seq.end()-1);
+    expair const & next_to_last_expair=*(seq.end()-2);
+    int seq_size = seq.size();
+
+    // *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric())
+    if ((!seq_copied) && (seq_size>=2) &&
+        is_ex_exactly_of_type(last_expair.rest,numeric) &&
+        ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
+        is_ex_exactly_of_type(next_to_last_expair.rest,numeric) &&
+        ex_to_numeric(next_to_last_expair.coeff).is_equal(numONE()) ) {
+        newseq=seq;
+        seq_copied=true;
+        it2=newseq.end()-1;
+        it1=it2-1;
+    }
+    while (seq_copied && (newseq.size()>=2) &&
+           is_ex_exactly_of_type((*it1).rest,numeric) &&
+           ex_to_numeric((*it1).coeff).is_equal(numONE()) &&
+           is_ex_exactly_of_type((*it2).rest,numeric) &&
+           ex_to_numeric((*it2).coeff).is_equal(numONE()) ) {
+        *it1=expair(ex_to_numeric((*it1).rest).mul_dyn(ex_to_numeric((*it2).rest)),exONE());
+        newseq.pop_back();
+        it2=newseq.end()-1;
+        it1=it2-1;
+    }
+
+    // *(...,x,1) -> *(...,x)
+    if ((!seq_copied) && (seq_size>=1) &&
+        (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
+        (ex_to_numeric(last_expair.rest).compare(numONE())==0)) {
+        newseq=seq;
+        seq_copied=true;
+        it2=newseq.end()-1;
+    }
+    if (seq_copied && (newseq.size()>=1) &&
+        (is_ex_exactly_of_type((*it2).rest,numeric)) &&
+        (ex_to_numeric((*it2).rest).compare(numONE())==0)) {
+        newseq.pop_back();
+        it2=newseq.end()-1;
+    }
+
+    // *(...,x,0) -> 0
+    if ((!seq_copied) && (seq_size>=1) &&
+        (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
+        (ex_to_numeric(last_expair.rest).is_zero())) {
+        return exZERO();
+    }
+    if (seq_copied && (newseq.size()>=1) &&
+        (is_ex_exactly_of_type((*it2).rest,numeric)) &&
+        (ex_to_numeric((*it2).rest).is_zero())) {
+        return exZERO();
+    }
+
+    // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
+    if ((!seq_copied) && (seq_size==2) &&
+        is_ex_exactly_of_type(next_to_last_expair.rest,add) &&
+        is_ex_exactly_of_type(last_expair.rest,numeric) &&
+        ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
+        (ex_to_numeric(next_to_last_expair.coeff).compare(numONE())==0)) {
+        add const & addref=ex_to_add(next_to_last_expair.rest);
+        epvector distrseq;
+        distrseq.reserve(addref.seq.size());
+        for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
+            distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
+                                   last_expair.rest));
+        }
+        // special treatment for the last element if it is numeric (to
+        // avoid terms like (2/3)*(3/2)) is no longer necessary, this
+        // is handled in add::combine_pair_with_coeff_to_pair()
+        return (new add(distrseq,1))->setflag(status_flags::dynallocated  |
+                                              status_flags::evaluated );
+    }
+    if (seq_copied && (newseq.size()==2) &&
+        is_ex_exactly_of_type(newseq[0].rest,add) &&
+        is_ex_exactly_of_type(newseq[1].rest,numeric) &&
+        ex_to_numeric(newseq[1].coeff).is_equal(numONE()) &&
+        (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
+        add const & addref=ex_to_add(newseq[0].rest);
+        epvector distrseq;
+        distrseq.reserve(addref.seq.size());
+        for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
+            distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
+                                   newseq[1].rest));
+        }
+        // special treatment for the last element if it is numeric (to
+        // avoid terms like (2/3)*(3/2)) is no longer necessary, this
+        // is handled in add::combine_pair_with_coeff_to_pair()
+        return (new add(distrseq,1))->setflag(status_flags::dynallocated  |
+                                              status_flags::evaluated );
+    }
+    
+    // *() -> 1
+    if ((!seq_copied) && (seq_size==0)) {
+        return exONE();
+    } else if (seq_copied && (newseq.size()==0)) {
+        return exONE();
+    }
+
+    // *(x) -> x
+    if ((!seq_copied) && (seq_size==1)) {
+        return recombine_pair_to_ex(*(seq.begin()));
+    } else if (seq_copied && (newseq.size()==1)) {
+        return recombine_pair_to_ex(*(newseq.begin()));
+    }
+
+    if (!seq_copied) return this->hold();
+
+    return (new mul(newseq,1))->setflag(status_flags::dynallocated  |
+                                        status_flags::evaluated );
+}
+*/
+
+ex mul::eval(int level) const
+{
+    // simplifications  *(...,x;0) -> 0
+    //                  *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
+    //                  *(x;1) -> x
+    //                  *(;c) -> c
+
+    debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
+
+    epvector * evaled_seqp=evalchildren(level);
+    if (evaled_seqp!=0) {
+        // do more evaluation later
+        return (new mul(evaled_seqp,overall_coeff))->
+                   setflag(status_flags::dynallocated);
+    }
+
+#ifdef DOASSERT
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
+               (!(ex_to_numeric((*cit).coeff).is_integer())));
+        ASSERT(!((*cit).is_numeric_with_coeff_1()));
+        if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
+            printtree(cerr,0);
+        }
+        ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
+        /* for paranoia */
+        expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
+        ASSERT(p.rest.is_equal((*cit).rest));
+        ASSERT(p.coeff.is_equal((*cit).coeff));
+        /* end paranoia */
+    }
+#endif // def DOASSERT
+
+    if (flags & status_flags::evaluated) {
+        ASSERT(seq.size()>0);
+        ASSERT((seq.size()>1)||!overall_coeff.is_equal(exONE()));
+        return *this;
+    }
+
+    int seq_size=seq.size();
+    if (overall_coeff.is_equal(exZERO())) {
+        // *(...,x;0) -> 0
+        return exZERO();
+    } else if (seq_size==0) {
+        // *(;c) -> c
+        return overall_coeff;
+    } else if ((seq_size==1)&&overall_coeff.is_equal(exONE())) {
+        // *(x;1) -> x
+        return recombine_pair_to_ex(*(seq.begin()));
+    } else if ((seq_size==1) &&
+               is_ex_exactly_of_type((*seq.begin()).rest,add) &&
+               ex_to_numeric((*seq.begin()).coeff).is_equal(numONE())) {
+        // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
+        add const & addref=ex_to_add((*seq.begin()).rest);
+        epvector distrseq;
+        distrseq.reserve(addref.seq.size());
+        for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
+            distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
+                                   overall_coeff));
+        }
+        return (new add(distrseq,
+                        ex_to_numeric(addref.overall_coeff).
+                        mul_dyn(ex_to_numeric(overall_coeff))))
+            ->setflag(status_flags::dynallocated  |
+                      status_flags::evaluated );
+    }
+    return this->hold();
+}
+
+/*
+ex mul::eval(int level) const
+{
+    // simplifications: *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
+    //                  *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
+    //                  *(...,x,1) -> +(...,x)
+    //                  *(...,x,0) -> 0
+    //                  *(+(x,y,...),c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
+    //                  *(x) -> x
+    //                  *() -> 1
+
+    debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
+
+    epvector newseq=seq;
+    epvector::iterator it1,it2;
+    
+    // *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
+    it2=newseq.end()-1;
+    it1=it2-1;
+    while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
+                               is_exactly_of_type(*(*it2).rest.bp,numeric)) {
+        *it1=expair(ex_to_numeric((*it1).rest).power(ex_to_numeric((*it1).coeff))
+                    .mul(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff))),exONE());
+        newseq.pop_back();
+        it2=newseq.end()-1;
+        it1=it2-1;
+    }
+
+    if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
+        // *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
+        *it2=expair(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff)),exONE());
+        // *(...,x,1) -> *(...,x)
+        if (static_cast<numeric &>(*(*it2).rest.bp).compare(numONE())==0) {
+            newseq.pop_back();
+            it2=newseq.end()-1;
+        }
+    }
+
+    // *(...,x,0) -> 0
+    if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
+        if (static_cast<numeric &>(*(*it2).rest.bp).is_zero()==0) {
+            return exZERO();
+        }
+    }
+
+    // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
+    if ((newseq.size()==2)&&is_ex_exactly_of_type(newseq[0].rest,add)&&
+        is_ex_exactly_of_type(newseq[1].rest,numeric)&&
+        (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
+        add const & addref=ex_to_add(newseq[0].rest);
+        numeric const & numref=ex_to_numeric(newseq[1].rest);
+        epvector distrseq;
+        distrseq.reserve(addref.seq.size());
+        for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
+            distrseq.push_back(expair((*cit).rest,ex_to_numeric((*cit).coeff).mul(numref)));
+        }
+        return (new add(distrseq,1))->setflag(status_flags::dynallocated  |
+                                              status_flags::evaluated );
+    }
+    
+    if (newseq.size()==0) {
+        // *() -> 1
+        return exONE();
+    } else if (newseq.size()==1) {
+        // *(x) -> x
+        return recombine_pair_to_ex(*newseq.begin());
+    }
+
+    return (new mul(newseq,1))->setflag(status_flags::dynallocated  |
+                                        status_flags::evaluated );
+}
+*/
+
+exvector mul::get_indices(void) const
+{
+    // return union of indices of factors
+    exvector iv;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        exvector subiv=(*cit).rest.get_indices();
+        iv.reserve(iv.size()+subiv.size());
+        for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
+            iv.push_back(*cit2);
+        }
+    }
+    return iv;
+}
+
+ex mul::simplify_ncmul(exvector const & v) const
+{
+    throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
+}
+
+// protected
+
+int mul::compare_same_type(basic const & other) const
+{
+    return expairseq::compare_same_type(other);
+}
+
+bool mul::is_equal_same_type(basic const & other) const
+{
+    return expairseq::is_equal_same_type(other);
+}
+
+unsigned mul::return_type(void) const
+{
+    if (seq.size()==0) {
+        // mul without factors: should not happen, but commutes
+        return return_types::commutative;
+    }
+
+    bool all_commutative=1;
+    unsigned rt;
+    epvector::const_iterator cit_noncommutative_element; // point to first found nc element
+
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        rt=(*cit).rest.return_type();
+        if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
+        if ((rt==return_types::noncommutative)&&(all_commutative)) {
+            // first nc element found, remember position
+            cit_noncommutative_element=cit;
+            all_commutative=0;
+        }
+        if ((rt==return_types::noncommutative)&&(!all_commutative)) {
+               // another nc element found, compare type_infos
+            if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
+               // diffent types -> mul is ncc
+               return return_types::noncommutative_composite;
+            }
+        }
+    }
+    // all factors checked
+    return all_commutative ? return_types::commutative : return_types::noncommutative;
+}
+   
+unsigned mul::return_type_tinfo(void) const
+{
+    if (seq.size()==0) {
+        // mul without factors: should not happen
+        return tinfo_key;
+    }
+    // return type_info of first noncommutative element
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        if ((*cit).rest.return_type()==return_types::noncommutative) {
+            return (*cit).rest.return_type_tinfo();
+        }
+    }
+    // no noncommutative element found, should not happen
+    return tinfo_key;
+}
+
+ex mul::thisexpairseq(epvector const & v, ex const & oc) const
+{
+    return (new mul(v,oc))->setflag(status_flags::dynallocated);
+}
+
+ex mul::thisexpairseq(epvector * vp, ex const & oc) const
+{
+    return (new mul(vp,oc))->setflag(status_flags::dynallocated);
+}
+
+expair mul::split_ex_to_pair(ex const & e) const
+{
+    if (is_ex_exactly_of_type(e,power)) {
+        power const & powerref=ex_to_power(e);
+        if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
+            return expair(powerref.basis,powerref.exponent);
+        }
+    }
+    return expair(e,exONE());
+}
+    
+expair mul::combine_ex_with_coeff_to_pair(ex const & e,
+                                          ex const & c) const
+{
+    // to avoid duplication of power simplification rules,
+    // we create a temporary power object
+    // otherwise it would be hard to correctly simplify
+    // expression like (4^(1/3))^(3/2)
+    if (are_ex_trivially_equal(c,exONE())) {
+        return split_ex_to_pair(e);
+    }
+    return split_ex_to_pair(power(e,c));
+}
+    
+expair mul::combine_pair_with_coeff_to_pair(expair const & p,
+                                            ex const & c) const
+{
+    // to avoid duplication of power simplification rules,
+    // we create a temporary power object
+    // otherwise it would be hard to correctly simplify
+    // expression like (4^(1/3))^(3/2)
+    if (are_ex_trivially_equal(c,exONE())) {
+        return p;
+    }
+    return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
+}
+    
+ex mul::recombine_pair_to_ex(expair const & p) const
+{
+    // if (p.coeff.compare(exONE())==0) {
+    // if (are_ex_trivially_equal(p.coeff,exONE())) {
+    if (ex_to_numeric(p.coeff).is_equal(numONE())) {
+        return p.rest;
+    } else {
+        return power(p.rest,p.coeff);
+    }
+}
+
+bool mul::expair_needs_further_processing(epp it)
+{
+    if (is_ex_exactly_of_type((*it).rest,mul) &&
+        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 (!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(numONE())) {
+            // combined pair has coeff 1 and must be moved to the end
+            return true;
+        }
+    }
+    return false;
+}       
+
+ex mul::default_overall_coeff(void) const
+{
+    return exONE();
+}
+
+void mul::combine_overall_coeff(ex const & c)
+{
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    ASSERT(is_ex_exactly_of_type(c,numeric));
+    overall_coeff = ex_to_numeric(overall_coeff).mul_dyn(ex_to_numeric(c));
+}
+
+void mul::combine_overall_coeff(ex const & c1, ex const & c2)
+{
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    ASSERT(is_ex_exactly_of_type(c1,numeric));
+    ASSERT(is_ex_exactly_of_type(c2,numeric));
+    overall_coeff = ex_to_numeric(overall_coeff).
+                        mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
+}
+
+bool mul::can_make_flat(expair const & p) const
+{
+    ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
+    // this assertion will probably fail somewhere
+    // it would require a more careful make_flat, obeying the power laws
+    // probably should return true only if p.coeff is integer
+    return ex_to_numeric(p.coeff).is_equal(numONE());
+}
+
+ex mul::expand(unsigned options) const
+{
+    exvector sub_expanded_seq;
+    intvector positions_of_adds;
+    intvector number_of_add_operands;
+
+    epvector * expanded_seqp=expandchildren(options);
+
+    epvector const & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
+
+    positions_of_adds.resize(expanded_seq.size());
+    number_of_add_operands.resize(expanded_seq.size());
+
+    int number_of_adds=0;
+    int number_of_expanded_terms=1;
+
+    unsigned current_position=0;
+    epvector::const_iterator last=expanded_seq.end();
+    for (epvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
+        if (is_ex_exactly_of_type((*cit).rest,add)&&
+            (ex_to_numeric((*cit).coeff).is_equal(numONE()))) {
+            positions_of_adds[number_of_adds]=current_position;
+            add const & expanded_addref=ex_to_add((*cit).rest);
+            int addref_nops=expanded_addref.nops();
+            number_of_add_operands[number_of_adds]=addref_nops;
+            number_of_expanded_terms *= addref_nops;
+            number_of_adds++;
+        }
+        current_position++;
+    }
+
+    if (number_of_adds==0) {
+        if (expanded_seqp==0) {
+            return this->setflag(status_flags::expanded);
+        }
+        return (new mul(expanded_seqp,overall_coeff))->
+                     setflag(status_flags::dynallocated ||
+                             status_flags::expanded);
+    }
+
+    exvector distrseq;
+    distrseq.reserve(number_of_expanded_terms);
+
+    intvector k;
+    k.resize(number_of_adds);
+    
+    int l;
+    for (l=0; l<number_of_adds; l++) {
+        k[l]=0;
+    }
+
+    while (1) {
+        epvector term;
+        term=expanded_seq;
+        for (l=0; l<number_of_adds; l++) {
+            add const & addref=ex_to_add(expanded_seq[positions_of_adds[l]].rest);
+            ASSERT(term[positions_of_adds[l]].coeff.compare(exONE())==0);
+            term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
+        }
+        /*
+        cout << "mul::expand() term begin" << endl;
+        for (epvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
+            cout << "rest" << endl;
+            (*cit).rest.printtree(cout);
+            cout << "coeff" << endl;
+            (*cit).coeff.printtree(cout);
+        }
+        cout << "mul::expand() term end" << endl;
+        */
+        distrseq.push_back((new mul(term,overall_coeff))->
+                                setflag(status_flags::dynallocated |
+                                        status_flags::expanded));
+
+        // increment k[]
+        l=number_of_adds-1;
+        while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
+            k[l]=0;    
+            l--;
+        }
+        if (l<0) break;
+    }
+
+    if (expanded_seqp!=0) {
+        delete expanded_seqp;
+    }
+    /*
+    cout << "mul::expand() distrseq begin" << endl;
+    for (exvector::const_iterator cit=distrseq.begin(); cit!=distrseq.end(); ++cit) {
+        (*cit).printtree(cout);
+    }
+    cout << "mul::expand() distrseq end" << endl;
+    */
+
+    return (new add(distrseq))->setflag(status_flags::dynallocated |
+                                        status_flags::expanded);
+}
+
+/*
+ex mul::expand(unsigned options) const
+{
+    exvector sub_expanded_seq;
+    intvector positions_of_adds;
+    intvector number_of_add_operands;
+
+    sub_expanded_seq.resize(seq.size());
+    positions_of_adds.resize(seq.size());
+    number_of_add_operands.reserve(seq.size());
+
+    int number_of_adds=0;
+    int number_of_expanded_terms=1;
+    for (unsigned current_position=0; current_position<seq.size(); current_position++) {
+        ex const & expanded_ex=recombine_pair_to_ex(seq[current_position]).expand(options);
+        if (is_ex_exactly_of_type(expanded_ex,add)) {
+            positions_of_adds[number_of_adds]=current_position;
+            add const & expanded_addref=ex_to_add(expanded_ex);
+            number_of_add_operands[number_of_adds]=expanded_addref.seq.size();
+            number_of_expanded_terms *= expanded_addref.seq.size();
+            number_of_adds++;
+        }
+        sub_expanded_seq.push_back(expanded_ex);
+    }
+
+    exvector distrseq;
+    distrseq.reserve(number_of_expanded_terms);
+
+    intvector k;
+    k.resize(number_of_adds);
+    
+    int l;
+    for (l=0; l<number_of_adds; l++) {
+        k[l]=0;
+    }
+
+    while (1) {
+        exvector term;
+        term=sub_expanded_seq;
+        for (l=0; l<number_of_adds; l++) {
+            add const & addref=ex_to_add(sub_expanded_seq[positions_of_adds[l]]);
+            term[positions_of_adds[l]]=addref.recombine_pair_to_ex(addref.seq[k[l]]);
+        }
+        distrseq.push_back((new mul(term))->setflag(status_flags::dynallocated |
+                                                    status_flags::expanded));
+
+        // increment k[]
+        l=number_of_adds-1;
+        while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
+            k[l]=0;    
+            l--;
+        }
+        if (l<0) break;
+    }
+
+    return (new add(distrseq))->setflag(status_flags::dynallocated |
+                                        status_flags::expanded);
+}
+*/
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+epvector * mul::expandchildren(unsigned options) const
+{
+    epvector::const_iterator last=seq.end();
+    epvector::const_iterator cit=seq.begin();
+    while (cit!=last) {
+        ex const & factor=recombine_pair_to_ex(*cit);
+        ex const & expanded_factor=factor.expand(options);
+        if (!are_ex_trivially_equal(factor,expanded_factor)) {
+
+            // something changed, copy seq, eval and return it
+            epvector *s=new epvector;
+            s->reserve(seq.size());
+
+            // copy parts of seq which are known not to have changed
+            epvector::const_iterator cit2=seq.begin();
+            while (cit2!=cit) {
+                s->push_back(*cit2);
+                ++cit2;
+            }
+            // copy first changed element
+            s->push_back(split_ex_to_pair(expanded_factor));
+            ++cit2;
+            // copy rest
+            while (cit2!=last) {
+                s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
+                ++cit2;
+            }
+            return s;
+        }
+        ++cit;
+    }
+    
+    return 0; // nothing has changed
+}
+   
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned mul::precedence=50;
+
+
+//////////
+// global constants
+//////////
+
+const mul some_mul;
+type_info const & typeid_mul=typeid(some_mul);
+
+
diff --git a/ginac/mul.h b/ginac/mul.h
new file mode 100644 (file)
index 0000000..6f951c9
--- /dev/null
@@ -0,0 +1,103 @@
+/** @file mul.h
+ *
+ *  Interface to GiNaC's products of expressions. */
+
+#ifndef _MUL_H_
+#define _MUL_H_
+
+class mul;
+
+#include "expairseq.h"
+
+/** Product of expressions. */
+class mul : public expairseq
+{
+    friend class add;
+    friend class ncmul;
+    friend class power;
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    mul();
+    ~mul();
+    mul(mul const & other);
+    mul const & operator=(mul const & other);
+protected:
+    void copy(mul const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    mul(ex const & lh, ex const & rh);
+    mul(exvector const & v);
+    mul(epvector const & v);
+    //mul(epvector const & v, bool do_not_canonicalize=0);
+    mul(epvector const & v, ex const & oc);
+    mul(epvector * vp, ex const & oc);
+    mul(ex const & lh, ex const & mh, ex const & rh);
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const;
+    bool info(unsigned inf) const;
+    int degree(symbol const & s) const;
+    int ldegree(symbol const & s) const;
+    ex coeff(symbol const & s, int const n=1) const;
+    ex eval(int level=0) const;
+    ex diff(symbol const & s) const;
+    ex series(symbol const & s, ex const & point, int order) const;
+    ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+    numeric integer_content(void) const;
+    ex smod(numeric const &xi) const;
+    numeric max_coefficient(void) const;
+    exvector get_indices(void) const;
+    ex simplify_ncmul(exvector const & v) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    ex thisexpairseq(epvector const & v, ex const & oc) const;
+    ex thisexpairseq(epvector * vp, ex const & oc) const;
+    void printpair(ostream & os, expair const & p,
+                   unsigned upper_precedence) const;
+    expair split_ex_to_pair(ex const & e) const;
+    expair combine_ex_with_coeff_to_pair(ex const & e,
+                                         ex const & c) const;
+    expair combine_pair_with_coeff_to_pair(expair const & p,
+                                           ex const & c) const;
+    ex recombine_pair_to_ex(expair const & p) const;
+    bool expair_needs_further_processing(epp it);
+    ex default_overall_coeff(void) const;
+    void combine_overall_coeff(ex const & c);
+    void combine_overall_coeff(ex const & c1, ex const & c2);
+    bool can_make_flat(expair const & p) const;
+    ex expand(unsigned options=0) const;
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+
+    // non-virtual functions in this class
+protected:
+    epvector * expandchildren(unsigned options) const;
+
+// member variables
+
+protected:
+    static unsigned precedence;
+};
+
+// global constants
+
+extern const mul some_mul;
+extern type_info const & typeid_mul;
+
+#define ex_to_mul(X) static_cast<mul const &>(*(X).bp)
+
+#endif // ndef _MUL_H_
+
diff --git a/ginac/ncmul.cpp b/ginac/ncmul.cpp
new file mode 100644 (file)
index 0000000..560f715
--- /dev/null
@@ -0,0 +1,570 @@
+/** @file ncmul.cpp
+ *
+ *  Implementation of GiNaC's non-commutative products of expressions. */
+
+#include <algorithm>
+#include <iostream>
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+ncmul::ncmul()
+{
+    debugmsg("ncmul default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_NCMUL;
+}
+
+ncmul::~ncmul()
+{
+    debugmsg("ncmul destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+ncmul::ncmul(ncmul const & other)
+{
+    debugmsg("ncmul copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+ncmul const & ncmul::operator=(ncmul const & other)
+{
+    debugmsg("ncmul operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void ncmul::copy(ncmul const & other)
+{
+    exprseq::copy(other);
+}
+
+void ncmul::destroy(bool call_parent)
+{
+    if (call_parent) exprseq::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+ncmul::ncmul(ex const & lh, ex const & rh) :
+    exprseq(lh,rh)
+{
+    debugmsg("ncmul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_NCMUL;
+}
+
+ncmul::ncmul(ex const & f1, ex const & f2, ex const & f3) :
+    exprseq(f1,f2,f3)
+{
+    debugmsg("ncmul constructor from 3 ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_NCMUL;
+}
+
+ncmul::ncmul(ex const & f1, ex const & f2, ex const & f3,
+      ex const & f4) : exprseq(f1,f2,f3,f4)
+{
+    debugmsg("ncmul constructor from 4 ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_NCMUL;
+}
+
+ncmul::ncmul(ex const & f1, ex const & f2, ex const & f3,
+      ex const & f4, ex const & f5) : exprseq(f1,f2,f3,f4,f5)
+{
+    debugmsg("ncmul constructor from 5 ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_NCMUL;
+}
+
+ncmul::ncmul(ex const & f1, ex const & f2, ex const & f3,
+      ex const & f4, ex const & f5, ex const & f6) :
+    exprseq(f1,f2,f3,f4,f5,f6)
+{
+    debugmsg("ncmul constructor from 6 ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_NCMUL;
+}
+
+ncmul::ncmul(exvector const & v, bool discardable) : exprseq(v,discardable)
+{
+    debugmsg("ncmul constructor from exvector,bool",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_NCMUL;
+}
+
+ncmul::ncmul(exvector * vp) : exprseq(vp)
+{
+    debugmsg("ncmul constructor from exvector *",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_NCMUL;
+}
+    
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * ncmul::duplicate() const
+{
+    debugmsg("ncmul duplicate",LOGLEVEL_ASSIGNMENT);
+    return new ncmul(*this);
+}
+
+bool ncmul::info(unsigned inf) const
+{
+    throw(std::logic_error("which flags have to be implemented in ncmul::info()?"));
+}
+
+typedef vector<int> intvector;
+
+ex ncmul::expand(unsigned options) const
+{
+    exvector sub_expanded_seq;
+    intvector positions_of_adds;
+    intvector number_of_add_operands;
+
+    exvector expanded_seq=expandchildren(options);
+
+    positions_of_adds.resize(expanded_seq.size());
+    number_of_add_operands.resize(expanded_seq.size());
+
+    int number_of_adds=0;
+    int number_of_expanded_terms=1;
+
+    unsigned current_position=0;
+    exvector::const_iterator last=expanded_seq.end();
+    for (exvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
+        if (is_ex_exactly_of_type((*cit),add)) {
+            positions_of_adds[number_of_adds]=current_position;
+            add const & expanded_addref=ex_to_add(*cit);
+            number_of_add_operands[number_of_adds]=expanded_addref.seq.size();
+            number_of_expanded_terms *= expanded_addref.seq.size();
+            number_of_adds++;
+        }
+        current_position++;
+    }
+
+    if (number_of_adds==0) {
+        return (new ncmul(expanded_seq,1))->setflag(status_flags::dynallocated ||
+                                                    status_flags::expanded);
+    }
+
+    exvector distrseq;
+    distrseq.reserve(number_of_expanded_terms);
+
+    intvector k;
+    k.resize(number_of_adds);
+    
+    int l;
+    for (l=0; l<number_of_adds; l++) {
+        k[l]=0;
+    }
+
+    while (1) {
+        exvector term;
+        term=expanded_seq;
+        for (l=0; l<number_of_adds; l++) {
+            ASSERT(is_ex_exactly_of_type(expanded_seq[positions_of_adds[l]],add));
+            add const & addref=ex_to_add(expanded_seq[positions_of_adds[l]]);
+            term[positions_of_adds[l]]=addref.recombine_pair_to_ex(addref.seq[k[l]]);
+        }
+        distrseq.push_back((new ncmul(term,1))->setflag(status_flags::dynallocated |
+                                                        status_flags::expanded));
+
+        // increment k[]
+        l=number_of_adds-1;
+        while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
+            k[l]=0;    
+            l--;
+        }
+        if (l<0) break;
+    }
+
+    return (new add(distrseq))->setflag(status_flags::dynallocated |
+                                        status_flags::expanded);
+}
+
+int ncmul::degree(symbol const & s) const
+{
+    int deg_sum=0;
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        deg_sum+=(*cit).degree(s);
+    }
+    return deg_sum;
+}
+
+int ncmul::ldegree(symbol const & s) const
+{
+    int deg_sum=0;
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        deg_sum+=(*cit).ldegree(s);
+    }
+    return deg_sum;
+}
+
+ex ncmul::coeff(symbol const & s, int const n) const
+{
+    exvector coeffseq;
+    coeffseq.reserve(seq.size());
+
+    if (n==0) {
+        // product of individual coeffs
+        // if a non-zero power of s is found, the resulting product will be 0
+        exvector::const_iterator it=seq.begin();
+        while (it!=seq.end()) {
+            coeffseq.push_back((*it).coeff(s,n));
+            ++it;
+        }
+        return (new ncmul(coeffseq,1))->setflag(status_flags::dynallocated);
+    }
+         
+    exvector::const_iterator it=seq.begin();
+    bool coeff_found=0;
+    while (it!=seq.end()) {
+        ex c=(*it).coeff(s,n);
+        if (!c.is_zero()) {
+            coeffseq.push_back(c);
+            coeff_found=1;
+        } else {
+            coeffseq.push_back(*it);
+        }
+        ++it;
+    }
+
+    if (coeff_found) return (new ncmul(coeffseq,1))->setflag(status_flags::dynallocated);
+    
+    return exZERO();
+}
+
+unsigned ncmul::count_factors(ex const & 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 (int i=0; i<e.nops(); i++) {
+            factors += count_factors(e.op(i));
+        }
+        return factors;
+    }
+    return 1;
+}
+        
+void ncmul::append_factors(exvector & v, ex const & e) const
+{
+    if ((is_ex_exactly_of_type(e,mul)&&(e.return_type()!=return_types::commutative))||
+        (is_ex_exactly_of_type(e,ncmul))) {
+        for (int i=0; i<e.nops(); i++) {
+            append_factors(v,e.op(i));
+        }
+        return;
+    }
+    v.push_back(e);
+}
+
+typedef vector<unsigned> unsignedvector;
+typedef vector<exvector> exvectorvector;
+
+ex ncmul::eval(int level) const
+{
+    // simplifications: ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
+    //                      ncmul(...,x1,x2,...,x3,x4,...) (associativity)
+    //                  ncmul(x) -> x
+    //                  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::eval_ncmul(x1,x2,x3,...)
+    // the following rule would be nice, but produces a recursion,
+    // which must be trapped by introducing a flag that the sub-ncmuls()
+    // are already evaluated (maybe later...)
+    //                  ncmul(x1,x2,...,X,y1,y2,...) ->
+    //                      ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
+    //                      (X noncommutative_composite)
+
+    if ((level==1)&&(flags & status_flags::evaluated)) {
+        return *this;
+    }
+
+    exvector evaledseq=evalchildren(level);
+
+    // ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
+    //     ncmul(...,x1,x2,...,x3,x4,...) (associativity)
+    unsigned factors=0;
+    for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
+        factors += count_factors(*cit);
+    }
+
+    exvector assocseq;
+    assocseq.reserve(factors);
+    for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
+        append_factors(assocseq,*cit);
+    }
+
+    // ncmul(x) -> x
+    if (assocseq.size()==1) return *(seq.begin());
+
+    // ncmul() -> 1
+    if (assocseq.size()==0) return exONE();
+
+    // 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;
+    for (exvector::const_iterator cit=assocseq.begin(); cit!=assocseq.end(); ++cit) {
+        switch (rettypes[i]=(*cit).return_type()) {
+        case return_types::commutative:
+            count_commutative++;
+            break;
+        case return_types::noncommutative:
+            count_noncommutative++;
+            break;
+        case return_types::noncommutative_composite:
+            count_noncommutative_composite++;
+            break;
+        default:
+            throw(std::logic_error("ncmul::eval(): invalid return type"));
+        }
+        ++i;
+    }
+    ASSERT(count_commutative+count_noncommutative+count_noncommutative_composite==assocseq.size());
+
+    // ncmul(...,c1,...,c2,...) ->
+    //     *(c1,c2,ncmul(...)) (pull out commutative elements)
+    if (count_commutative!=0) {
+        exvector commutativeseq;
+        commutativeseq.reserve(count_commutative+1);
+        exvector noncommutativeseq;
+        noncommutativeseq.reserve(assocseq.size()-count_commutative);
+        for (i=0; i<assocseq.size(); ++i) {
+            if (rettypes[i]==return_types::commutative) {
+                commutativeseq.push_back(assocseq[i]);
+            } else {
+                noncommutativeseq.push_back(assocseq[i]);
+            }
+        }
+        commutativeseq.push_back((new ncmul(noncommutativeseq,1))->
+                                  setflag(status_flags::dynallocated));
+        return (new mul(commutativeseq))->setflag(status_flags::dynallocated);
+    }
+        
+    // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
+    //     (collect elements of same type)
+
+    if (count_noncommutative_composite==0) {
+        // there are neither commutative nor noncommutative_composite
+        // elements in assocseq
+        ASSERT(count_commutative==0);
+
+        exvectorvector evv;
+        unsignedvector rttinfos;
+        evv.reserve(assocseq.size());
+        rttinfos.reserve(assocseq.size());
+
+        for (exvector::const_iterator cit=assocseq.begin(); cit!=assocseq.end(); ++cit) {
+            unsigned ti=(*cit).return_type_tinfo();
+            // search type in vector of known types
+            for (i=0; i<rttinfos.size(); ++i) {
+                if (ti==rttinfos[i]) {
+                    evv[i].push_back(*cit);
+                    break;
+                }
+            }
+            if (i>=rttinfos.size()) {
+                // new type
+                rttinfos.push_back(ti);
+                evv.push_back(exvector());
+                (*(evv.end()-1)).reserve(assocseq.size());
+                (*(evv.end()-1)).push_back(*cit);
+            }
+        }
+
+#ifdef DOASSERT
+        ASSERT(evv.size()==rttinfos.size());
+        ASSERT(evv.size()>0);
+        unsigned s=0;
+        for (i=0; i<evv.size(); ++i) {
+            s += evv[i].size();
+        }
+        ASSERT(s==assocseq.size());
+#endif // def DOASSERT
+        
+        // if all elements are of same type, simplify the string
+        if (evv.size()==1) {
+            return evv[0][0].simplify_ncmul(evv[0]);
+        }
+        
+        exvector splitseq;
+        splitseq.reserve(evv.size());
+        for (i=0; i<evv.size(); ++i) {
+            splitseq.push_back((new ncmul(evv[i]))->
+                               setflag(status_flags::dynallocated));
+        }
+
+        return (new mul(splitseq))->setflag(status_flags::dynallocated);
+    }
+    
+    return (new ncmul(assocseq))->setflag(status_flags::dynallocated |
+                                          status_flags::evaluated);
+}
+
+exvector ncmul::get_indices(void) const
+{
+    // return union of indices of factors
+    exvector iv;
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        exvector subiv=(*cit).get_indices();
+        iv.reserve(iv.size()+subiv.size());
+        for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
+            iv.push_back(*cit2);
+        }
+    }
+    return iv;
+}
+
+ex ncmul::subs(lst const & ls, lst const & lr) const
+{
+    return ncmul(subschildren(ls, lr));
+}
+
+ex ncmul::thisexprseq(exvector const & v) const
+{
+    return (new ncmul(v))->setflag(status_flags::dynallocated);
+}
+
+ex ncmul::thisexprseq(exvector * vp) const
+{
+    return (new ncmul(vp))->setflag(status_flags::dynallocated);
+}
+
+// protected
+
+int ncmul::compare_same_type(basic const & other) const
+{
+    return exprseq::compare_same_type(other);
+}
+
+unsigned ncmul::return_type(void) const
+{
+    if (seq.size()==0) {
+        // ncmul without factors: should not happen, but commutes
+        return return_types::commutative;
+    }
+
+    bool all_commutative=1;
+    unsigned rt;
+    exvector::const_iterator cit_noncommutative_element; // point to first found nc element
+
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        rt=(*cit).return_type();
+        if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
+        if ((rt==return_types::noncommutative)&&(all_commutative)) {
+            // first nc element found, remember position
+            cit_noncommutative_element=cit;
+            all_commutative=0;
+        }
+        if ((rt==return_types::noncommutative)&&(!all_commutative)) {
+           // another nc element found, compare type_infos
+            if ((*cit_noncommutative_element).return_type_tinfo()!=(*cit).return_type_tinfo()) {
+               // diffent types -> mul is ncc
+               return return_types::noncommutative_composite;
+            }
+        }
+    }
+    // all factors checked
+    ASSERT(!all_commutative); // not all factors should commute, because this is a ncmul();
+    return all_commutative ? return_types::commutative : return_types::noncommutative;
+}
+   
+unsigned ncmul::return_type_tinfo(void) const
+{
+    if (seq.size()==0) {
+        // mul without factors: should not happen
+        return tinfo_key;
+    }
+    // return type_info of first noncommutative element
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        if ((*cit).return_type()==return_types::noncommutative) {
+            return (*cit).return_type_tinfo();
+        }
+    }
+    // no noncommutative element found, should not happen
+    return tinfo_key;
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+exvector ncmul::expandchildren(unsigned options) const
+{
+    exvector s;
+    s.reserve(seq.size());
+
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        s.push_back((*it).expand(options));
+    }
+    return s;
+}
+
+exvector const & ncmul::get_factors(void) const
+{
+    return seq;
+}
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned ncmul::precedence=50;
+
+
+//////////
+// global constants
+//////////
+
+const ncmul some_ncmul;
+type_info const & typeid_ncmul=typeid(some_ncmul);
+
+//////////
+// friend functions
+//////////
+
+ex nonsimplified_ncmul(exvector const & v)
+{
+    return (new ncmul(v))->setflag(status_flags::dynallocated);
+}
+
+ex simplified_ncmul(exvector const & v)
+{
+    if (v.size()==0) {
+        return exONE();
+    } else if (v.size()==1) {
+        return v[0];
+    }
+    return (new ncmul(v))->setflag(status_flags::dynallocated |
+                                   status_flags::evaluated);
+}
+
+
diff --git a/ginac/ncmul.h b/ginac/ncmul.h
new file mode 100644 (file)
index 0000000..1b833b0
--- /dev/null
@@ -0,0 +1,96 @@
+/** @file ncmul.h
+ *
+ *  Interface to GiNaC's non-commutative products of expressions. */
+
+#ifndef _NCMUL_H_
+#define _NCMUL_H_
+
+#include "exprseq.h"
+
+class ncmul;
+
+/** Non-commutative product of expressions. */
+class ncmul : public exprseq
+{
+    friend class power;
+    friend ex nonsimplified_ncmul(exvector const & v);
+    friend ex simplified_ncmul(exvector const & v);
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    ncmul();
+    ~ncmul();
+    ncmul(ncmul const & other);
+    ncmul const & operator=(ncmul const & other);
+protected:
+    void copy(ncmul const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    ncmul(ex const & lh, ex const & rh);
+    ncmul(ex const & f1, ex const & f2, ex const & f3);
+    ncmul(ex const & f1, ex const & f2, ex const & f3,
+          ex const & f4);
+    ncmul(ex const & f1, ex const & f2, ex const & f3,
+          ex const & f4, ex const & f5);
+    ncmul(ex const & f1, ex const & f2, ex const & f3,
+          ex const & f4, ex const & f5, ex const & f6);
+    ncmul(exvector const & v, bool discardable=false);
+    ncmul(exvector * vp); // vp will be deleted
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence) const;
+    void printcsrc(ostream & os, unsigned upper_precedence) const;
+    bool info(unsigned inf) const;
+    int degree(symbol const & s) const;
+    int ldegree(symbol const & s) const;
+    ex expand(unsigned options=0) const;
+    ex coeff(symbol const & s, int const n=1) const;
+    ex eval(int level=0) const;
+    ex diff(symbol const & s) const;
+    ex subs(lst const & ls, lst const & lr) const;
+    exvector get_indices(void) const;
+    ex thisexprseq(exvector const & v) const;
+    ex thisexprseq(exvector * vp) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+
+    // non-virtual functions in this class
+protected:
+    unsigned count_factors(ex const & e) const;
+    void append_factors(exvector & v, ex const & e) const;
+    exvector expandchildren(unsigned options) const;
+public:
+    exvector const & get_factors(void) const;
+
+// member variables
+
+protected:
+    static unsigned precedence;
+};
+
+// global constants
+
+extern const ncmul some_ncmul;
+extern type_info const & typeid_ncmul;
+
+// friend funtions 
+
+ex nonsimplified_ncmul(exvector const & v);
+ex simplified_ncmul(exvector const & v);
+
+#define ex_to_ncmul(X) static_cast<ncmul const &>(*(X).bp)
+
+#endif // ndef _NCMUL_H_
+
diff --git a/ginac/normal.cpp b/ginac/normal.cpp
new file mode 100644 (file)
index 0000000..614b1db
--- /dev/null
@@ -0,0 +1,1452 @@
+/** @file normal.cpp
+ *
+ *  This file implements several functions that work on univariate and
+ *  multivariate polynomials and rational functions.
+ *  These functions include polynomial quotient and remainder, GCD and LCM
+ *  computation, square-free factorization and rational function normalization.
+ */
+
+#include <stdexcept>
+
+#include "ginac.h"
+
+// If comparing expressions (ex::compare()) is fast, you can set this to 1.
+// Some routines like quo(), rem() and gcd() will then return a quick answer
+// when they are called with two identical arguments.
+#define FAST_COMPARE 1
+
+// Set this if you want divide_in_z() to use remembering
+#define USE_REMEMBER 1
+
+
+/** Return pointer to first symbol found in expression.  Due to GiNaC´s
+ *  internal ordering of terms, it may not be obvious which symbol this
+ *  function returns for a given expression.
+ *
+ *  @param e  expression to search
+ *  @param x  pointer to first symbol found (returned)
+ *  @return "false" if no symbol was found, "true" otherwise */
+
+static bool get_first_symbol(const ex &e, const symbol *&x)
+{
+    if (is_ex_exactly_of_type(e, symbol)) {
+        x = static_cast<symbol *>(e.bp);
+        return true;
+    } else if (is_ex_exactly_of_type(e, add) || is_ex_exactly_of_type(e, mul)) {
+        for (int i=0; i<e.nops(); i++)
+            if (get_first_symbol(e.op(i), x))
+                return true;
+    } else if (is_ex_exactly_of_type(e, power)) {
+        if (get_first_symbol(e.op(0), x))
+            return true;
+    }
+    return false;
+}
+
+
+/*
+ *  Statistical information about symbols in polynomials
+ */
+
+#include <algorithm>
+
+/** This structure holds information about the highest and lowest degrees
+ *  in which a symbol appears in two multivariate polynomials "a" and "b".
+ *  A vector of these structures with information about all symbols in
+ *  two polynomials can be created with the function get_symbol_stats().
+ *
+ *  @see get_symbol_stats */
+struct sym_desc {
+    /** Pointer to symbol */
+    const symbol *sym;
+
+    /** Highest degree of symbol in polynomial "a" */
+    int deg_a;
+
+    /** Highest degree of symbol in polynomial "b" */
+    int deg_b;
+
+    /** Lowest degree of symbol in polynomial "a" */
+    int ldeg_a;
+
+    /** Lowest degree of symbol in polynomial "b" */
+    int ldeg_b;
+
+    /** Minimum of ldeg_a and ldeg_b (Used for sorting) */
+    int min_deg;
+
+    /** Commparison operator for sorting */
+    bool operator<(const sym_desc &x) const {return min_deg < x.min_deg;}
+};
+
+// Vector of sym_desc structures
+typedef vector<sym_desc> sym_desc_vec;
+
+// Add symbol the sym_desc_vec (used internally by get_symbol_stats())
+static void add_symbol(const symbol *s, sym_desc_vec &v)
+{
+    sym_desc_vec::iterator it = v.begin(), itend = v.end();
+    while (it != itend) {
+        if (it->sym->compare(*s) == 0)  // If it's already in there, don't add it a second time
+            return;
+        it++;
+    }
+    sym_desc d;
+    d.sym = s;
+    v.push_back(d);
+}
+
+// Collect all symbols of an expression (used internally by get_symbol_stats())
+static void collect_symbols(const ex &e, sym_desc_vec &v)
+{
+    if (is_ex_exactly_of_type(e, symbol)) {
+        add_symbol(static_cast<symbol *>(e.bp), v);
+    } else if (is_ex_exactly_of_type(e, add) || is_ex_exactly_of_type(e, mul)) {
+        for (int i=0; i<e.nops(); i++)
+            collect_symbols(e.op(i), v);
+    } else if (is_ex_exactly_of_type(e, power)) {
+        collect_symbols(e.op(0), v);
+    }
+}
+
+/** Collect statistical information about symbols in polynomials.
+ *  This function fills in a vector of "sym_desc" structs which contain
+ *  information about the highest and lowest degrees of all symbols that
+ *  appear in two polynomials. The vector is then sorted by minimum
+ *  degree (lowest to highest). The information gathered by this
+ *  function is used by the GCD routines to identify trivial factors
+ *  and to determine which variable to choose as the main variable
+ *  for GCD computation.
+ *
+ *  @param a  first multivariate polynomial
+ *  @param b  second multivariate polynomial
+ *  @param v  vector of sym_desc structs (filled in) */
+
+static void get_symbol_stats(const ex &a, const ex &b, sym_desc_vec &v)
+{
+    collect_symbols(a.eval(), v);   // eval() to expand assigned symbols
+    collect_symbols(b.eval(), v);
+    sym_desc_vec::iterator it = v.begin(), itend = v.end();
+    while (it != itend) {
+        int deg_a = a.degree(*(it->sym));
+        int deg_b = b.degree(*(it->sym));
+        it->deg_a = deg_a;
+        it->deg_b = deg_b;
+        it->min_deg = min(deg_a, deg_b);
+        it->ldeg_a = a.ldegree(*(it->sym));
+        it->ldeg_b = b.ldegree(*(it->sym));
+        it++;
+    }
+    sort(v.begin(), v.end());
+}
+
+
+/*
+ *  Computation of LCM of denominators of coefficients of a polynomial
+ */
+
+// Compute LCM of denominators of coefficients by going through the
+// expression recursively (used internally by lcm_of_coefficients_denominators())
+static numeric lcmcoeff(const ex &e, const numeric &l)
+{
+    if (e.info(info_flags::rational))
+        return lcm(ex_to_numeric(e).denom(), l);
+    else if (is_ex_exactly_of_type(e, add) || is_ex_exactly_of_type(e, mul)) {
+        numeric c = numONE();
+        for (int i=0; i<e.nops(); i++) {
+            c = lcmcoeff(e.op(i), c);
+        }
+        return lcm(c, l);
+    } else if (is_ex_exactly_of_type(e, power))
+        return lcmcoeff(e.op(0), l);
+    return l;
+}
+
+/** Compute LCM of denominators of coefficients of a polynomial.
+ *  Given a polynomial with rational coefficients, this function computes
+ *  the LCM of the denominators of all coefficients. This can be used
+ *  To bring a polynomial from Q[X] to Z[X].
+ *
+ *  @param e  multivariate polynomial
+ *  @return LCM of denominators of coefficients */
+
+static numeric lcm_of_coefficients_denominators(const ex &e)
+{
+    return lcmcoeff(e.expand(), numONE());
+}
+
+
+/** Compute the integer content (= GCD of all numeric coefficients) of an
+ *  expanded polynomial.
+ *
+ *  @param e  expanded polynomial
+ *  @return integer content */
+
+numeric ex::integer_content(void) const
+{
+    ASSERT(bp!=0);
+    return bp->integer_content();
+}
+
+numeric basic::integer_content(void) const
+{
+    return numONE();
+}
+
+numeric numeric::integer_content(void) const
+{
+    return abs(*this);
+}
+
+numeric add::integer_content(void) const
+{
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    numeric c = numZERO();
+    while (it != itend) {
+        ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
+        ASSERT(is_ex_exactly_of_type(it->coeff,numeric));
+        c = gcd(ex_to_numeric(it->coeff), c);
+        it++;
+    }
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    c = gcd(ex_to_numeric(overall_coeff),c);
+    return c;
+}
+
+numeric mul::integer_content(void) const
+{
+#ifdef DOASSERT
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    while (it != itend) {
+        ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
+        ++it;
+    }
+#endif // def DOASSERT
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    return abs(ex_to_numeric(overall_coeff));
+}
+
+
+/*
+ *  Polynomial quotients and remainders
+ */
+
+/** Quotient q(x) of polynomials a(x) and b(x) in Q[x].
+ *  It satisfies a(x)=b(x)*q(x)+r(x).
+ *
+ *  @param a  first polynomial in x (dividend)
+ *  @param b  second polynomial in x (divisor)
+ *  @param x  a and b are polynomials in x
+ *  @param check_args  check whether a and b are polynomials with rational
+ *         coefficients (defaults to "true")
+ *  @return quotient of a and b in Q[x] */
+
+ex quo(const ex &a, const ex &b, const symbol &x, bool check_args)
+{
+    if (b.is_zero())
+        throw(std::overflow_error("quo: division by zero"));
+    if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric))
+        return a / b;
+#if FAST_COMPARE
+    if (a.is_equal(b))
+        return exONE();
+#endif
+    if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
+        throw(std::invalid_argument("quo: arguments must be polynomials over the rationals"));
+
+    // Polynomial long division
+    ex q = exZERO();
+    ex r = a.expand();
+    if (r.is_zero())
+        return r;
+    int bdeg = b.degree(x);
+    int rdeg = r.degree(x);
+    ex blcoeff = b.expand().coeff(x, bdeg);
+    bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
+    while (rdeg >= bdeg) {
+        ex term, rcoeff = r.coeff(x, rdeg);
+        if (blcoeff_is_numeric)
+            term = rcoeff / blcoeff;
+        else {
+            if (!divide(rcoeff, blcoeff, term, false))
+                return *new ex(fail());
+        }
+        term *= power(x, rdeg - bdeg);
+        q += term;
+        r -= (term * b).expand();
+        if (r.is_zero())
+            break;
+        rdeg = r.degree(x);
+    }
+    return q;
+}
+
+
+/** Remainder r(x) of polynomials a(x) and b(x) in Q[x].
+ *  It satisfies a(x)=b(x)*q(x)+r(x).
+ *
+ *  @param a  first polynomial in x (dividend)
+ *  @param b  second polynomial in x (divisor)
+ *  @param x  a and b are polynomials in x
+ *  @param check_args  check whether a and b are polynomials with rational
+ *         coefficients (defaults to "true")
+ *  @return remainder of a(x) and b(x) in Q[x] */
+
+ex rem(const ex &a, const ex &b, const symbol &x, bool check_args)
+{
+    if (b.is_zero())
+        throw(std::overflow_error("rem: division by zero"));
+    if (is_ex_exactly_of_type(a, numeric)) {
+        if  (is_ex_exactly_of_type(b, numeric))
+            return exZERO();
+        else
+            return b;
+    }
+#if FAST_COMPARE
+    if (a.is_equal(b))
+        return exZERO();
+#endif
+    if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
+        throw(std::invalid_argument("rem: arguments must be polynomials over the rationals"));
+
+    // Polynomial long division
+    ex r = a.expand();
+    if (r.is_zero())
+        return r;
+    int bdeg = b.degree(x);
+    int rdeg = r.degree(x);
+    ex blcoeff = b.expand().coeff(x, bdeg);
+    bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
+    while (rdeg >= bdeg) {
+        ex term, rcoeff = r.coeff(x, rdeg);
+        if (blcoeff_is_numeric)
+            term = rcoeff / blcoeff;
+        else {
+            if (!divide(rcoeff, blcoeff, term, false))
+                return *new ex(fail());
+        }
+        term *= power(x, rdeg - bdeg);
+        r -= (term * b).expand();
+        if (r.is_zero())
+            break;
+        rdeg = r.degree(x);
+    }
+    return r;
+}
+
+
+/** Pseudo-remainder of polynomials a(x) and b(x) in Z[x].
+ *
+ *  @param a  first polynomial in x (dividend)
+ *  @param b  second polynomial in x (divisor)
+ *  @param x  a and b are polynomials in x
+ *  @param check_args  check whether a and b are polynomials with rational
+ *         coefficients (defaults to "true")
+ *  @return pseudo-remainder of a(x) and b(x) in Z[x] */
+
+ex prem(const ex &a, const ex &b, const symbol &x, bool check_args)
+{
+    if (b.is_zero())
+        throw(std::overflow_error("prem: division by zero"));
+    if (is_ex_exactly_of_type(a, numeric)) {
+        if (is_ex_exactly_of_type(b, numeric))
+            return exZERO();
+        else
+            return b;
+    }
+    if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
+        throw(std::invalid_argument("prem: arguments must be polynomials over the rationals"));
+
+    // Polynomial long division
+    ex r = a.expand();
+    ex eb = b.expand();
+    int rdeg = r.degree(x);
+    int bdeg = eb.degree(x);
+    ex blcoeff;
+    if (bdeg <= rdeg) {
+        blcoeff = eb.coeff(x, bdeg);
+        if (bdeg == 0)
+            eb = exZERO();
+        else
+            eb -= blcoeff * power(x, bdeg);
+    } else
+        blcoeff = exONE();
+
+    int delta = rdeg - bdeg + 1, i = 0;
+    while (rdeg >= bdeg && !r.is_zero()) {
+        ex rlcoeff = r.coeff(x, rdeg);
+        ex term = (power(x, rdeg - bdeg) * eb * rlcoeff).expand();
+        if (rdeg == 0)
+            r = exZERO();
+        else
+            r -= rlcoeff * power(x, rdeg);
+        r = (blcoeff * r).expand() - term;
+        rdeg = r.degree(x);
+        i++;
+    }
+    return power(blcoeff, delta - i) * r;
+}
+
+
+/** Exact polynomial division of a(X) by b(X) in Q[X].
+ *  
+ *  @param a  first multivariate polynomial (dividend)
+ *  @param b  second multivariate polynomial (divisor)
+ *  @param q  quotient (returned)
+ *  @param check_args  check whether a and b are polynomials with rational
+ *         coefficients (defaults to "true")
+ *  @return "true" when exact division succeeds (quotient returned in q),
+ *          "false" otherwise */
+
+bool divide(const ex &a, const ex &b, ex &q, bool check_args)
+{
+    q = exZERO();
+    if (b.is_zero())
+        throw(std::overflow_error("divide: division by zero"));
+    if (is_ex_exactly_of_type(b, numeric)) {
+        q = a / b;
+        return true;
+    } else if (is_ex_exactly_of_type(a, numeric))
+        return false;
+#if FAST_COMPARE
+    if (a.is_equal(b)) {
+        q = exONE();
+        return true;
+    }
+#endif
+    if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)))
+        throw(std::invalid_argument("divide: arguments must be polynomials over the rationals"));
+
+    // Find first symbol
+    const symbol *x;
+    if (!get_first_symbol(a, x) && !get_first_symbol(b, x))
+        throw(std::invalid_argument("invalid expression in divide()"));
+
+    // Polynomial long division (recursive)
+    ex r = a.expand();
+    if (r.is_zero())
+        return true;
+    int bdeg = b.degree(*x);
+    int rdeg = r.degree(*x);
+    ex blcoeff = b.expand().coeff(*x, bdeg);
+    bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric);
+    while (rdeg >= bdeg) {
+        ex term, rcoeff = r.coeff(*x, rdeg);
+        if (blcoeff_is_numeric)
+            term = rcoeff / blcoeff;
+        else
+            if (!divide(rcoeff, blcoeff, term, false))
+                return false;
+        term *= power(*x, rdeg - bdeg);
+        q += term;
+        r -= (term * b).expand();
+        if (r.is_zero())
+            return true;
+        rdeg = r.degree(*x);
+    }
+    return false;
+}
+
+
+#if USE_REMEMBER
+/*
+ *  Remembering
+ */
+
+#include <map>
+
+typedef pair<ex, ex> ex2;
+typedef pair<ex, bool> exbool;
+
+struct ex2_less {
+    bool operator() (const ex2 p, const ex2 q) const 
+    {
+        return p.first.compare(q.first) < 0 || (!(q.first.compare(p.first) < 0) && p.second.compare(q.second) < 0);        
+    }
+};
+
+typedef map<ex2, exbool, ex2_less> ex2_exbool_remember;
+#endif
+
+
+/** Exact polynomial division of a(X) by b(X) in Z[X].
+ *  This functions works like divide() but the input and output polynomials are
+ *  in Z[X] instead of Q[X] (i.e. they have integer coefficients). Unlike
+ *  divide(), it doesn´t check whether the input polynomials really are integer
+ *  polynomials, so be careful of what you pass in. Also, you have to run
+ *  get_symbol_stats() over the input polynomials before calling this function
+ *  and pass an iterator to the first element of the sym_desc vector. This
+ *  function is used internally by the heur_gcd().
+ *  
+ *  @param a  first multivariate polynomial (dividend)
+ *  @param b  second multivariate polynomial (divisor)
+ *  @param q  quotient (returned)
+ *  @param var  iterator to first element of vector of sym_desc structs
+ *  @return "true" when exact division succeeds (the quotient is returned in
+ *          q), "false" otherwise.
+ *  @see get_symbol_stats, heur_gcd */
+static bool divide_in_z(const ex &a, const ex &b, ex &q, sym_desc_vec::const_iterator var)
+{
+    q = exZERO();
+    if (b.is_zero())
+        throw(std::overflow_error("divide_in_z: division by zero"));
+    if (b.is_equal(exONE())) {
+        q = a;
+        return true;
+    }
+    if (is_ex_exactly_of_type(a, numeric)) {
+        if (is_ex_exactly_of_type(b, numeric)) {
+            q = a / b;
+            return q.info(info_flags::integer);
+        } else
+            return false;
+    }
+#if FAST_COMPARE
+    if (a.is_equal(b)) {
+        q = exONE();
+        return true;
+    }
+#endif
+
+#if USE_REMEMBER
+    // Remembering
+    static ex2_exbool_remember dr_remember;
+    ex2_exbool_remember::const_iterator remembered = dr_remember.find(ex2(a, b));
+    if (remembered != dr_remember.end()) {
+        q = remembered->second.first;
+        return remembered->second.second;
+    }
+#endif
+
+    // Main symbol
+    const symbol *x = var->sym;
+
+    // Compare degrees
+    int adeg = a.degree(*x), bdeg = b.degree(*x);
+    if (bdeg > adeg)
+        return false;
+
+#if 1
+
+    // Polynomial long division (recursive)
+    ex r = a.expand();
+    if (r.is_zero())
+        return true;
+    int rdeg = adeg;
+    ex eb = b.expand();
+    ex blcoeff = eb.coeff(*x, bdeg);
+    while (rdeg >= bdeg) {
+        ex term, rcoeff = r.coeff(*x, rdeg);
+        if (!divide_in_z(rcoeff, blcoeff, term, var+1))
+            break;
+        term = (term * power(*x, rdeg - bdeg)).expand();
+        q += term;
+        r -= (term * eb).expand();
+        if (r.is_zero()) {
+#if USE_REMEMBER
+            dr_remember[ex2(a, b)] = exbool(q, true);
+#endif
+            return true;
+        }
+        rdeg = r.degree(*x);
+    }
+#if USE_REMEMBER
+    dr_remember[ex2(a, b)] = exbool(q, false);
+#endif
+    return false;
+
+#else
+
+    // Trial division using polynomial interpolation
+    int i, k;
+
+    // Compute values at evaluation points 0..adeg
+    vector<numeric> alpha; alpha.reserve(adeg + 1);
+    exvector u; u.reserve(adeg + 1);
+    numeric point = numZERO();
+    ex c;
+    for (i=0; i<=adeg; i++) {
+        ex bs = b.subs(*x == point);
+        while (bs.is_zero()) {
+            point += numONE();
+            bs = b.subs(*x == point);
+        }
+        if (!divide_in_z(a.subs(*x == point), bs, c, var+1))
+            return false;
+        alpha.push_back(point);
+        u.push_back(c);
+        point += numONE();
+    }
+
+    // Compute inverses
+    vector<numeric> rcp; rcp.reserve(adeg + 1);
+    rcp.push_back(0);
+    for (k=1; k<=adeg; k++) {
+        numeric product = alpha[k] - alpha[0];
+        for (i=1; i<k; i++)
+            product *= alpha[k] - alpha[i];
+        rcp.push_back(product.inverse());
+    }
+
+    // Compute Newton coefficients
+    exvector v; v.reserve(adeg + 1);
+    v.push_back(u[0]);
+    for (k=1; k<=adeg; k++) {
+        ex temp = v[k - 1];
+        for (i=k-2; i>=0; i--)
+            temp = temp * (alpha[k] - alpha[i]) + v[i];
+        v.push_back((u[k] - temp) * rcp[k]);
+    }
+
+    // Convert from Newton form to standard form
+    c = v[adeg];
+    for (k=adeg-1; k>=0; k--)
+        c = c * (*x - alpha[k]) + v[k];
+
+    if (c.degree(*x) == (adeg - bdeg)) {
+        q = c.expand();
+        return true;
+    } else
+        return false;
+#endif
+}
+
+
+/*
+ *  Separation of unit part, content part and primitive part of polynomials
+ */
+
+/** Compute unit part (= sign of leading coefficient) of a multivariate
+ *  polynomial in Z[x]. The product of unit part, content part, and primitive
+ *  part is the polynomial itself.
+ *
+ *  @param x  variable in which to compute the unit part
+ *  @return unit part
+ *  @see ex::content, ex::primpart */
+ex ex::unit(const symbol &x) const
+{
+    ex c = expand().lcoeff(x);
+    if (is_ex_exactly_of_type(c, numeric))
+        return c < exZERO() ? exMINUSONE() : exONE();
+    else {
+        const symbol *y;
+        if (get_first_symbol(c, y))
+            return c.unit(*y);
+        else
+            throw(std::invalid_argument("invalid expression in unit()"));
+    }
+}
+
+
+/** Compute content part (= unit normal GCD of all coefficients) of a
+ *  multivariate polynomial in Z[x].  The product of unit part, content part,
+ *  and primitive part is the polynomial itself.
+ *
+ *  @param x  variable in which to compute the content part
+ *  @return content part
+ *  @see ex::unit, ex::primpart */
+ex ex::content(const symbol &x) const
+{
+    if (is_zero())
+        return exZERO();
+    if (is_ex_exactly_of_type(*this, numeric))
+        return info(info_flags::negative) ? -*this : *this;
+    ex e = expand();
+    if (e.is_zero())
+        return exZERO();
+
+    // First, try the integer content
+    ex c = e.integer_content();
+    ex r = e / c;
+    ex lcoeff = r.lcoeff(x);
+    if (lcoeff.info(info_flags::integer))
+        return c;
+
+    // GCD of all coefficients
+    int deg = e.degree(x);
+    int ldeg = e.ldegree(x);
+    if (deg == ldeg)
+        return e.lcoeff(x) / e.unit(x);
+    c = exZERO();
+    for (int i=ldeg; i<=deg; i++)
+        c = gcd(e.coeff(x, i), c, NULL, NULL, false);
+    return c;
+}
+
+
+/** Compute primitive part of a multivariate polynomial in Z[x].
+ *  The product of unit part, content part, and primitive part is the
+ *  polynomial itself.
+ *
+ *  @param x  variable in which to compute the primitive part
+ *  @return primitive part
+ *  @see ex::unit, ex::content */
+ex ex::primpart(const symbol &x) const
+{
+    if (is_zero())
+        return exZERO();
+    if (is_ex_exactly_of_type(*this, numeric))
+        return exONE();
+
+    ex c = content(x);
+    if (c.is_zero())
+        return exZERO();
+    ex u = unit(x);
+    if (is_ex_exactly_of_type(c, numeric))
+        return *this / (c * u);
+    else
+        return quo(*this, c * u, x, false);
+}
+
+
+/** Compute primitive part of a multivariate polynomial in Z[x] when the
+ *  content part is already known. This function is faster in computing the
+ *  primitive part than the previous function.
+ *
+ *  @param x  variable in which to compute the primitive part
+ *  @param c  previously computed content part
+ *  @return primitive part */
+
+ex ex::primpart(const symbol &x, const ex &c) const
+{
+    if (is_zero())
+        return exZERO();
+    if (c.is_zero())
+        return exZERO();
+    if (is_ex_exactly_of_type(*this, numeric))
+        return exONE();
+
+    ex u = unit(x);
+    if (is_ex_exactly_of_type(c, numeric))
+        return *this / (c * u);
+    else
+        return quo(*this, c * u, x, false);
+}
+
+
+/*
+ *  GCD of multivariate polynomials
+ */
+
+/** Compute GCD of multivariate polynomials using the subresultant PRS
+ *  algorithm. This function is used internally gy gcd().
+ *
+ *  @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 sr_gcd(const ex &a, const ex &b, const symbol *x)
+{
+    // 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 subresultant sequence
+    ex r = exZERO(), ri = exONE(), psi = exONE();
+    int delta = cdeg - ddeg;
+
+    for (;;) {
+        // Calculate polynomial pseudo-remainder
+        r = prem(c, d, *x, false);
+        if (r.is_zero())
+            return gamma * d.primpart(*x);
+        c = d;
+        cdeg = ddeg;
+        if (!divide(r, ri * power(psi, delta), d, false))
+            throw(std::runtime_error("invalid expression in sr_gcd(), division failed"));
+        ddeg = d.degree(*x);
+        if (ddeg == 0) {
+            if (is_ex_exactly_of_type(r, numeric))
+                return gamma;
+            else
+                return gamma * r.primpart(*x);
+        }
+
+        // Next element of subresultant sequence
+        ri = c.expand().lcoeff(*x);
+        if (delta == 1)
+            psi = ri;
+        else if (delta)
+            divide(power(ri, delta), power(psi, delta-1), psi, false);
+        delta = cdeg - ddeg;
+    }
+}
+
+
+/** Return maximum (absolute value) coefficient of a polynomial.
+ *  This function is used internally by heur_gcd().
+ *
+ *  @param e  expanded multivariate polynomial
+ *  @return maximum coefficient
+ *  @see heur_gcd */
+
+numeric ex::max_coefficient(void) const
+{
+    ASSERT(bp!=0);
+    return bp->max_coefficient();
+}
+
+numeric basic::max_coefficient(void) const
+{
+    return numONE();
+}
+
+numeric numeric::max_coefficient(void) const
+{
+    return abs(*this);
+}
+
+numeric add::max_coefficient(void) const
+{
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    numeric cur_max = abs(ex_to_numeric(overall_coeff));
+    while (it != itend) {
+        numeric a;
+        ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
+        a = abs(ex_to_numeric(it->coeff));
+        if (a > cur_max)
+            cur_max = a;
+        it++;
+    }
+    return cur_max;
+}
+
+numeric mul::max_coefficient(void) const
+{
+#ifdef DOASSERT
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    while (it != itend) {
+        ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
+        it++;
+    }
+#endif // def DOASSERT
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    return abs(ex_to_numeric(overall_coeff));
+}
+
+
+/** Apply symmetric modular homomorphism to a multivariate polynomial.
+ *  This function is used internally by heur_gcd().
+ *
+ *  @param e  expanded multivariate polynomial
+ *  @param xi  modulus
+ *  @return mapped polynomial
+ *  @see heur_gcd */
+
+ex ex::smod(const numeric &xi) const
+{
+    ASSERT(bp!=0);
+    return bp->smod(xi);
+}
+
+ex basic::smod(const numeric &xi) const
+{
+    return *this;
+}
+
+ex numeric::smod(const numeric &xi) const
+{
+    return ::smod(*this, xi);
+}
+
+ex add::smod(const numeric &xi) const
+{
+    epvector newseq;
+    newseq.reserve(seq.size()+1);
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    while (it != itend) {
+        ASSERT(!is_ex_exactly_of_type(it->rest,numeric));
+        numeric coeff = ::smod(ex_to_numeric(it->coeff), xi);
+        if (!coeff.is_zero())
+            newseq.push_back(expair(it->rest, coeff));
+        it++;
+    }
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    numeric coeff = ::smod(ex_to_numeric(overall_coeff), xi);
+    return (new add(newseq,coeff))->setflag(status_flags::dynallocated);
+}
+
+ex mul::smod(const numeric &xi) const
+{
+#ifdef DOASSERT
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    while (it != itend) {
+        ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*it),numeric));
+        it++;
+    }
+#endif // def DOASSERT
+    mul * mulcopyp=new mul(*this);
+    ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
+    mulcopyp->overall_coeff=::smod(ex_to_numeric(overall_coeff),xi);
+    mulcopyp->clearflag(status_flags::evaluated);
+    mulcopyp->clearflag(status_flags::hash_calculated);
+    return mulcopyp->setflag(status_flags::dynallocated);
+}
+
+
+/** Exception thrown by heur_gcd() to signal failure */
+class gcdheu_failed {};
+
+/** Compute GCD of multivariate polynomials using the heuristic GCD algorithm.
+ *  get_symbol_stats() must have been called previously with the input
+ *  polynomials and an iterator to the first element of the sym_desc vector
+ *  passed in. This function is used internally by gcd().
+ *
+ *  @param a  first multivariate polynomial (expanded)
+ *  @param b  second multivariate polynomial (expanded)
+ *  @param ca  cofactor of polynomial a (returned), NULL to suppress
+ *             calculation of cofactor
+ *  @param cb  cofactor of polynomial b (returned), NULL to suppress
+ *             calculation of cofactor
+ *  @param var iterator to first element of vector of sym_desc structs
+ *  @return the GCD as a new expression
+ *  @see gcd
+ *  @exception gcdheu_failed() */
+
+static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const_iterator var)
+{
+    if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) {
+        numeric g = gcd(ex_to_numeric(a), ex_to_numeric(b));
+        numeric rg;
+        if (ca || cb)
+            rg = g.inverse();
+        if (ca)
+            *ca = ex_to_numeric(a).mul(rg);
+        if (cb)
+            *cb = ex_to_numeric(b).mul(rg);
+        return g;
+    }
+
+    // The first symbol is our main variable
+    const symbol *x = var->sym;
+
+    // Remove integer content
+    numeric gc = gcd(a.integer_content(), b.integer_content());
+    numeric rgc = gc.inverse();
+    ex p = a * rgc;
+    ex q = b * rgc;
+    int maxdeg = max(p.degree(*x), q.degree(*x));
+
+    // Find evaluation point
+    numeric mp = p.max_coefficient(), mq = q.max_coefficient();
+    numeric xi;
+    if (mp > mq)
+        xi = mq * numTWO() + numTWO();
+    else
+        xi = mp * numTWO() + numTWO();
+
+    // 6 tries maximum
+    for (int t=0; t<6; t++) {
+        if (xi.int_length() * maxdeg > 50000)
+            throw gcdheu_failed();
+
+        // Apply evaluation homomorphism and calculate GCD
+        ex gamma = heur_gcd(p.subs(*x == xi), q.subs(*x == xi), NULL, NULL, var+1).expand();
+        if (!is_ex_exactly_of_type(gamma, fail)) {
+
+            // Reconstruct polynomial from GCD of mapped polynomials
+            ex g = exZERO();
+            numeric rxi = xi.inverse();
+            for (int i=0; !gamma.is_zero(); i++) {
+                ex gi = gamma.smod(xi);
+                g += gi * power(*x, i);
+                gamma = (gamma - gi) * rxi;
+            }
+            // Remove integer content
+            g /= g.integer_content();
+
+            // If the calculated polynomial divides both a and b, this is the GCD
+            ex dummy;
+            if (divide_in_z(p, g, ca ? *ca : dummy, var) && divide_in_z(q, g, cb ? *cb : dummy, var)) {
+                g *= gc;
+                ex lc = g.lcoeff(*x);
+                if (is_ex_exactly_of_type(lc, numeric) && lc.compare(exZERO()) < 0)
+                    return -g;
+                else
+                    return g;
+            }
+        }
+
+        // Next evaluation point
+        xi = iquo(xi * isqrt(isqrt(xi)) * numeric(73794), numeric(27011));
+    }
+    return *new ex(fail());
+}
+
+
+/** Compute GCD (Greatest Common Divisor) of multivariate polynomials a(X)
+ *  and b(X) in Z[X].
+ *
+ *  @param a  first multivariate polynomial
+ *  @param b  second multivariate polynomial
+ *  @param check_args  check whether a and b are polynomials with rational
+ *         coefficients (defaults to "true")
+ *  @return the GCD as a new expression */
+
+ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args)
+{
+    // Some trivial cases
+    if (a.is_zero()) {
+        if (ca)
+            *ca = exZERO();
+        if (cb)
+            *cb = exONE();
+        return b;
+    }
+    if (b.is_zero()) {
+        if (ca)
+            *ca = exONE();
+        if (cb)
+            *cb = exZERO();
+        return a;
+    }
+    if (a.is_equal(exONE()) || b.is_equal(exONE())) {
+        if (ca)
+            *ca = a;
+        if (cb)
+            *cb = b;
+        return exONE();
+    }
+#if FAST_COMPARE
+    if (a.is_equal(b)) {
+        if (ca)
+            *ca = exONE();
+        if (cb)
+            *cb = exONE();
+        return a;
+    }
+#endif
+    if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) {
+        numeric g = gcd(ex_to_numeric(a), ex_to_numeric(b));
+        if (ca)
+            *ca = ex_to_numeric(a) / g;
+        if (cb)
+            *cb = ex_to_numeric(b) / g;
+        return g;
+    }
+    if (check_args && !a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial)) {
+        cerr << "a=" << a << endl;
+        cerr << "b=" << b << endl;
+        throw(std::invalid_argument("gcd: arguments must be polynomials over the rationals"));
+    }
+
+    // Gather symbol statistics
+    sym_desc_vec sym_stats;
+    get_symbol_stats(a, b, sym_stats);
+
+    // The symbol with least degree is our main variable
+    sym_desc_vec::const_iterator var = sym_stats.begin();
+    const symbol *x = var->sym;
+
+    // Cancel trivial common factor
+    int ldeg_a = var->ldeg_a;
+    int ldeg_b = var->ldeg_b;
+    int min_ldeg = min(ldeg_a, ldeg_b);
+    if (min_ldeg > 0) {
+        ex common = power(*x, min_ldeg);
+//clog << "trivial common factor " << common << endl;
+        return gcd((a / common).expand(), (b / common).expand(), ca, cb, false) * common;
+    }
+
+    // Try to eliminate variables
+    if (var->deg_a == 0) {
+//clog << "eliminating variable " << *x << " from b" << endl;
+        ex c = b.content(*x);
+        ex g = gcd(a, c, ca, cb, false);
+        if (cb)
+            *cb *= b.unit(*x) * b.primpart(*x, c);
+        return g;
+    } else if (var->deg_b == 0) {
+//clog << "eliminating variable " << *x << " from a" << endl;
+        ex c = a.content(*x);
+        ex g = gcd(c, b, ca, cb, false);
+        if (ca)
+            *ca *= a.unit(*x) * a.primpart(*x, c);
+        return g;
+    }
+
+    // Try heuristic algorithm first, fall back to PRS if that failed
+    ex g;
+    try {
+        g = heur_gcd(a.expand(), b.expand(), ca, cb, var);
+    } catch (gcdheu_failed) {
+        g = *new ex(fail());
+    }
+    if (is_ex_exactly_of_type(g, fail)) {
+//clog << "heuristics failed\n";
+        g = sr_gcd(a, b, x);
+        if (ca)
+            divide(a, g, *ca, false);
+        if (cb)
+            divide(b, g, *cb, false);
+    }
+    return g;
+}
+
+
+/** Compute LCM (Least Common Multiple) of multivariate polynomials in Z[X].
+ *
+ *  @param a  first multivariate polynomial
+ *  @param b  second multivariate polynomial
+ *  @param check_args  check whether a and b are polynomials with rational
+ *         coefficients (defaults to "true")
+ *  @return the LCM as a new expression */
+ex lcm(const ex &a, const ex &b, bool check_args)
+{
+    if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric))
+        return gcd(ex_to_numeric(a), ex_to_numeric(b));
+    if (check_args && !a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))
+        throw(std::invalid_argument("lcm: arguments must be polynomials over the rationals"));
+    
+    ex ca, cb;
+    ex g = gcd(a, b, &ca, &cb, false);
+    return ca * cb * g;
+}
+
+
+/*
+ *  Square-free factorization
+ */
+
+// Univariate GCD of polynomials in Q[x] (used internally by sqrfree()).
+// a and b can be multivariate polynomials but they are treated as univariate polynomials in x.
+static ex univariate_gcd(const ex &a, const ex &b, const symbol &x)
+{
+    if (a.is_zero())
+        return b;
+    if (b.is_zero())
+        return a;
+    if (a.is_equal(exONE()) || b.is_equal(exONE()))
+        return exONE();
+    if (is_ex_of_type(a, numeric) && is_ex_of_type(b, numeric))
+        return gcd(ex_to_numeric(a), ex_to_numeric(b));
+    if (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))
+        throw(std::invalid_argument("univariate_gcd: arguments must be polynomials over the rationals"));
+
+    // Euclidean algorithm
+    ex c, d, r;
+    if (a.degree(x) >= b.degree(x)) {
+        c = a;
+        d = b;
+    } else {
+        c = b;
+        d = a;
+    }
+    for (;;) {
+        r = rem(c, d, x, false);
+        if (r.is_zero())
+            break;
+        c = d;
+        d = r;
+    }
+    return d / d.lcoeff(x);
+}
+
+
+/** Compute square-free factorization of multivariate polynomial a(x) using
+ *  Yun´s algorithm.
+ *
+ * @param a  multivariate polynomial
+ * @param x  variable to factor in
+ * @return factored polynomial */
+ex sqrfree(const ex &a, const symbol &x)
+{
+    int i = 1;
+    ex res = exONE();
+    ex b = a.diff(x);
+    ex c = univariate_gcd(a, b, x);
+    ex w;
+    if (c.is_equal(exONE())) {
+        w = a;
+    } else {
+        w = quo(a, c, x);
+        ex y = quo(b, c, x);
+        ex z = y - w.diff(x);
+        while (!z.is_zero()) {
+            ex g = univariate_gcd(w, z, x);
+            res *= power(g, i);
+            w = quo(w, g, x);
+            y = quo(z, g, x);
+            z = y - w.diff(x);
+            i++;
+        }
+    }
+    return res * power(w, i);
+}
+
+
+/*
+ *  Normal form of rational functions
+ */
+
+// Create a symbol for replacing the expression "e" (or return a previously
+// assigned symbol). The symbol is appended to sym_list and returned, the
+// expression is appended to repl_list.
+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 (int i=0; i<repl_lst.nops(); i++)
+        if (repl_lst.op(i).is_equal(e))
+            return sym_lst.op(i);
+
+    // Otherwise create new symbol and add to list, taking care that the
+       // replacement expression doesn't contain symbols from the sym_lst
+       // because subs() is not recursive
+       symbol s;
+       ex es(s);
+       ex e_replaced = e.subs(sym_lst, repl_lst);
+    sym_lst.append(es);
+    repl_lst.append(e_replaced);
+    return es;
+}
+
+
+/** Default implementation of ex::normal(). It replaces the object with a
+ *  temporary symbol.
+ *  @see ex::normal */
+ex basic::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    return replace_with_symbol(*this, sym_lst, repl_lst);
+}
+
+
+/** Implementation of ex::normal() for symbols. This returns the unmodifies symbol.
+ *  @see ex::normal */
+ex symbol::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    return *this;
+}
+
+
+/** Implementation of ex::normal() for a numeric. It splits complex numbers
+ *  into re+I*im and replaces I and non-rational real numbers with a temporary
+ *  symbol.
+ *  @see ex::normal */
+ex numeric::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    if (is_real())
+        if (is_rational())
+            return *this;
+               else
+                   return replace_with_symbol(*this, sym_lst, repl_lst);
+    else { // complex
+        numeric re = real(), im = imag();
+               ex re_ex = re.is_rational() ? re : replace_with_symbol(re, sym_lst, repl_lst);
+               ex im_ex = im.is_rational() ? im : replace_with_symbol(im, sym_lst, repl_lst);
+               return re_ex + im_ex * replace_with_symbol(I, sym_lst, repl_lst);
+       }
+}
+
+
+/*
+ *  Helper function for fraction cancellation (returns cancelled fraction n/d)
+ */
+
+static ex frac_cancel(const ex &n, const ex &d)
+{
+    ex num = n;
+    ex den = d;
+    ex pre_factor = exONE();
+
+    // Handle special cases where numerator or denominator is 0
+    if (num.is_zero())
+        return exZERO();
+    if (den.expand().is_zero())
+        throw(std::overflow_error("frac_cancel: division by zero in frac_cancel"));
+
+    // More special cases
+    if (is_ex_exactly_of_type(den, numeric))
+        return num / den;
+    if (num.is_zero())
+        return exZERO();
+
+    // Bring numerator and denominator to Z[X] by multiplying with
+    // LCM of all coefficients' denominators
+    ex num_lcm = lcm_of_coefficients_denominators(num);
+    ex den_lcm = lcm_of_coefficients_denominators(den);
+    num *= num_lcm;
+    den *= den_lcm;
+    pre_factor = den_lcm / num_lcm;
+
+    // Cancel GCD from numerator and denominator
+    ex cnum, cden;
+    if (gcd(num, den, &cnum, &cden, false) != exONE()) {
+               num = cnum;
+               den = cden;
+       }
+
+       // Make denominator unit normal (i.e. coefficient of first symbol
+       // as defined by get_first_symbol() is made positive)
+       const symbol *x;
+       if (get_first_symbol(den, x)) {
+               if (den.unit(*x).compare(exZERO()) < 0) {
+                       num *= exMINUSONE();
+                       den *= exMINUSONE();
+               }
+       }
+    return pre_factor * num / den;
+}
+
+
+/** Implementation of ex::normal() for a sum. It expands terms and performs
+ *  fractional addition.
+ *  @see ex::normal */
+ex add::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    // Normalize and expand children
+    exvector o;
+    o.reserve(seq.size()+1);
+    epvector::const_iterator it = seq.begin(), itend = seq.end();
+    while (it != itend) {
+        ex n = recombine_pair_to_ex(*it).bp->normal(sym_lst, repl_lst, level-1).expand();
+        if (is_ex_exactly_of_type(n, add)) {
+            epvector::const_iterator bit = (static_cast<add *>(n.bp))->seq.begin(), bitend = (static_cast<add *>(n.bp))->seq.end();
+            while (bit != bitend) {
+                o.push_back(recombine_pair_to_ex(*bit));
+                bit++;
+            }
+            o.push_back((static_cast<add *>(n.bp))->overall_coeff);
+        } else
+            o.push_back(n);
+        it++;
+    }
+    o.push_back(overall_coeff.bp->normal(sym_lst, repl_lst, level-1));
+
+    // Determine common denominator
+    ex den = exONE();
+    exvector::const_iterator ait = o.begin(), aitend = o.end();
+    while (ait != aitend) {
+        den = lcm((*ait).denom(false), den, false);
+        ait++;
+    }
+
+    // Add fractions
+    if (den.is_equal(exONE()))
+        return (new add(o))->setflag(status_flags::dynallocated);
+    else {
+        exvector num_seq;
+        for (ait=o.begin(); ait!=aitend; ait++) {
+            ex q;
+            if (!divide(den, (*ait).denom(false), q, false)) {
+                // should not happen
+                throw(std::runtime_error("invalid expression in add::normal, division failed"));
+            }
+            num_seq.push_back((*ait).numer(false) * q);
+        }
+        ex num = add(num_seq);
+
+        // Cancel common factors from num/den
+        return frac_cancel(num, den);
+    }
+}
+
+
+/** Implementation of ex::normal() for a product. It cancels common factors
+ *  from fractions.
+ *  @see ex::normal() */
+ex mul::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    // Normalize children
+    exvector o;
+    o.reserve(seq.size()+1);
+    epvector::const_iterator it = seq.begin(), itend = seq.end();
+    while (it != itend) {
+        o.push_back(recombine_pair_to_ex(*it).bp->normal(sym_lst, repl_lst, level-1));
+        it++;
+    }
+    o.push_back(overall_coeff.bp->normal(sym_lst, repl_lst, level-1));
+    ex n = (new mul(o))->setflag(status_flags::dynallocated);
+    return frac_cancel(n.numer(false), n.denom(false));
+}
+
+
+/** Implementation of ex::normal() for powers. It normalizes the basis,
+ *  distributes integer exponents to numerator and denominator, and replaces
+ *  non-integer powers by temporary symbols.
+ *  @see ex::normal */
+ex power::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    if (exponent.info(info_flags::integer)) {
+        // Integer powers are distributed
+        ex n = basis.bp->normal(sym_lst, repl_lst, level-1);
+        ex num = n.numer(false);
+        ex den = n.denom(false);
+        return power(num, exponent) / power(den, exponent);
+    } else {
+        // Non-integer powers are replaced by temporary symbol (after normalizing basis)
+        ex n = power(basis.bp->normal(sym_lst, repl_lst, level-1), exponent);
+        return replace_with_symbol(n, sym_lst, repl_lst);
+    }
+}
+
+
+/** Implementation of ex::normal() for series. It normalizes each coefficient and
+ *  replaces the series by a temporary symbol.
+ *  @see ex::normal */
+ex series::normal(lst &sym_lst, lst &repl_lst, int level) const
+{
+    epvector new_seq;
+    new_seq.reserve(seq.size());
+
+    epvector::const_iterator it = seq.begin(), itend = seq.end();
+    while (it != itend) {
+        new_seq.push_back(expair(it->rest.normal(), it->coeff));
+        it++;
+    }
+
+    ex n = series(var, point, new_seq);
+    return replace_with_symbol(n, sym_lst, repl_lst);
+}
+
+
+/** Normalization of rational functions.
+ *  This function converts an expression to its normal form
+ *  "numerator/denominator", where numerator and denominator are (relatively
+ *  prime) polynomials. Any subexpressions which are not rational functions
+ *  (like non-rational numbers, non-integer powers or functions like Sin(),
+ *  Cos() etc.) are replaced by temporary symbols which are re-substituted by
+ *  the (normalized) subexpressions before normal() returns (this way, any
+ *  expression can be treated as a rational function). normal() is applied
+ *  recursively to arguments of functions etc.
+ *
+ *  @param level maximum depth of recursion
+ *  @return normalized expression */
+ex ex::normal(int level) const
+{
+    lst sym_lst, repl_lst;
+    ex e = bp->normal(sym_lst, repl_lst, level);
+    if (sym_lst.nops() > 0)
+        return e.subs(sym_lst, repl_lst);
+    else
+        return e;
+}
diff --git a/ginac/normal.h b/ginac/normal.h
new file mode 100644 (file)
index 0000000..451d155
--- /dev/null
@@ -0,0 +1,35 @@
+/** @file normal.h
+ *
+ *  Functions for polynomial quotient and remainder, GCD and LCM computation
+ *  and square-free factorization. */
+
+#ifndef NORMAL_H
+#define NORMAL_H
+
+#include "ex.h"
+
+class symbol;
+
+
+// Quotient q(x) of polynomials a(x) and b(x) in Q[x], so that a(x)=b(x)*q(x)+r(x)
+extern ex quo(const ex &a, const ex &b, const symbol &x, bool check_args = true);
+
+// Remainder r(x) of polynomials a(x) and b(x) in Q[x], so that a(x)=b(x)*q(x)+r(x)
+extern ex rem(const ex &a, const ex &b, const symbol &x, bool check_args = true);
+
+// Pseudo-remainder of polynomials a(x) and b(x) in Z[x]
+extern ex prem(const ex &a, const ex &b, const symbol &x, bool check_args = true);
+
+// Exact polynomial division of a(X) by b(X) in Q[X] (quotient returned in q), returns false when exact division fails
+extern bool divide(const ex &a, const ex &b, ex &q, bool check_args = true);
+
+// Polynomial GCD in Z[X], cofactors are returned in ca and cb, if desired
+extern ex gcd(const ex &a, const ex &b, ex *ca = NULL, ex *cb = NULL, bool check_args = true);
+
+// Polynomial LCM in Z[X]
+extern ex lcm(const ex &a, const ex &b, bool check_args = true);
+
+// Square-free factorization of a polynomial a(x)
+extern ex sqrfree(const ex &a, const symbol &x);
+
+#endif
diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp
new file mode 100644 (file)
index 0000000..c189c3d
--- /dev/null
@@ -0,0 +1,1341 @@
+/** @file numeric.cpp
+ *
+ *  This file contains the interface to the underlying bignum package.
+ *  Its most important design principle is to completely hide the inner
+ *  working of that other package from the user of GiNaC.  It must either 
+ *  provide implementation of arithmetic operators and numerical evaluation
+ *  of special functions or implement the interface to the bignum package. */
+
+#include <vector>
+#include <stdexcept>
+
+#include "ginac.h"
+
+// CLN should not pollute the global namespace, hence we include it here
+// instead of in some header file where it would propagate to other parts:
+#ifdef HAVE_CLN_CLN_H
+#include <CLN/cln.h>
+#else
+#include <cln.h>
+#endif
+
+// linker has no problems finding text symbols for numerator or denominator
+//#define SANE_LINKER
+
+//////////
+// default constructor, destructor, copy constructor assignment
+// operator and helpers
+//////////
+
+// public
+
+/** default ctor. Numerically it initializes to an integer zero. */
+numeric::numeric() : basic(TINFO_NUMERIC)
+{
+    debugmsg("numeric default constructor", LOGLEVEL_CONSTRUCT);
+    value = new cl_N;
+    *value=cl_I(0);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+numeric::~numeric()
+{
+    debugmsg("numeric destructor" ,LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+numeric::numeric(numeric const & other)
+{
+    debugmsg("numeric copy constructor", LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+numeric const & numeric::operator=(numeric const & other)
+{
+    debugmsg("numeric operator=", LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void numeric::copy(numeric const & other)
+{
+    basic::copy(other);
+    value = new cl_N(*other.value);
+}
+
+void numeric::destroy(bool call_parent)
+{
+    delete value;
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+numeric::numeric(int i) : basic(TINFO_NUMERIC)
+{
+    debugmsg("numeric constructor from int",LOGLEVEL_CONSTRUCT);
+    // Not the whole int-range is available if we don't cast to long
+    // first. This is due to the behaviour of the cl_I-ctor, which
+    // emphasizes efficiency:
+    value = new cl_I((long) i);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+numeric::numeric(unsigned int i) : basic(TINFO_NUMERIC)
+{
+    debugmsg("numeric constructor from uint",LOGLEVEL_CONSTRUCT);
+    // Not the whole uint-range is available if we don't cast to ulong
+    // first. This is due to the behaviour of the cl_I-ctor, which
+    // emphasizes efficiency:
+    value = new cl_I((unsigned long)i);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+numeric::numeric(long i) : basic(TINFO_NUMERIC)
+{
+    debugmsg("numeric constructor from long",LOGLEVEL_CONSTRUCT);
+    value = new cl_I(i);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+numeric::numeric(unsigned long i) : basic(TINFO_NUMERIC)
+{
+    debugmsg("numeric constructor from ulong",LOGLEVEL_CONSTRUCT);
+    value = new cl_I(i);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+/** Ctor for rational numerics a/b.
+ *
+ *  @exception overflow_error (division by zero) */
+numeric::numeric(long numer, long denom) : basic(TINFO_NUMERIC)
+{
+    debugmsg("numeric constructor from long/long",LOGLEVEL_CONSTRUCT);
+    if (!denom)
+        throw (std::overflow_error("division by zero"));
+    value = new cl_I(numer);
+    *value = *value / cl_I(denom);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+numeric::numeric(double d) : basic(TINFO_NUMERIC)
+{
+    debugmsg("numeric constructor from double",LOGLEVEL_CONSTRUCT);
+    // We really want to explicitly use the type cl_LF instead of the
+    // more general cl_F, since that would give us a cl_DF only which
+    // will not be promoted to cl_LF if overflow occurs:
+    value = new cl_N;
+    *value = cl_float(d, cl_default_float_format);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+numeric::numeric(char const *s) : basic(TINFO_NUMERIC)
+{   // MISSING: treatment of complex and ints and rationals.
+    debugmsg("numeric constructor from string",LOGLEVEL_CONSTRUCT);
+    if (strchr(s, '.'))
+        value = new cl_LF(s);
+    else
+        value = new cl_I(s);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+/** Ctor from CLN types.  This is for the initiated user or internal use
+ *  only. */
+numeric::numeric(cl_N const & z) : basic(TINFO_NUMERIC)
+{
+    debugmsg("numeric constructor from cl_N", LOGLEVEL_CONSTRUCT);
+    value = new cl_N(z);
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * numeric::duplicate() const
+{
+    debugmsg("numeric duplicate", LOGLEVEL_DUPLICATE);
+    return new numeric(*this);
+}
+
+// The method printraw doesn't do much, it simply uses CLN's operator<<() for
+// output, which is ugly but reliable. Examples:
+// 2+2i 
+void numeric::printraw(ostream & os) const
+{
+    debugmsg("numeric printraw", LOGLEVEL_PRINT);
+    os << "numeric(" << *value << ")";
+}
+
+// The method print adds to the output so it blends more consistently together
+// with the other routines.
+void numeric::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("numeric print", LOGLEVEL_PRINT);
+    if (is_real()) {  
+        // case 1, real:  x  or  -x
+        if ((realpart(*value) < 0) && (precedence <= upper_precedence)) {
+            os << "(" << *value << ")";
+        } else {
+            os << *value;
+        }
+    } else {
+        // case 2, imaginary:  y*I  or  -y*I
+        if (realpart(*value) == 0) {
+            if ((imagpart(*value) < 0) && (precedence <= upper_precedence)) {
+                if (imagpart(*value) == -1) {
+                    os << "(-I)";
+                } else {
+                    os << "(" << imagpart(*value) << "*I)";
+                }
+            } else {
+                if (imagpart(*value) == 1) {
+                    os << "I";
+                } else {
+                    if (imagpart (*value) == -1) {
+                        os << "-I";
+                    } else {
+                        os << imagpart(*value) << "*I";
+                    }
+                }
+            }
+        } else {
+            // case 3, complex:  x+y*I  or  x-y*I  or  -x+y*I  or  -x-y*I
+            if ((realpart(*value) < 0) && (precedence <= upper_precedence)) {
+                os << "(" << realpart(*value);
+                if (imagpart(*value) < 0) {
+                    if (imagpart(*value) == -1) {
+                        os << "-I)";
+                    } else {
+                        os << imagpart(*value) << "*I)";
+                    }
+                } else {
+                    if (imagpart(*value) == 1) {
+                        os << "+I)";
+                    } else {
+                        os << "+" << imagpart(*value) << "*I)";
+                    }
+                }
+            } else {
+                os << realpart(*value);
+                if (imagpart(*value) < 0) {
+                    if (imagpart(*value) == -1) {
+                        os << "-I";
+                    } else {
+                        os << imagpart(*value) << "*I";
+                    }
+                } else {
+                    if (imagpart(*value) == 1) {
+                        os << "+I";
+                    } else {
+                        os << "+" << imagpart(*value) << "*I";
+                    }
+                }
+            }
+        }
+    }
+}
+
+bool numeric::info(unsigned inf) const
+{
+    switch (inf) {
+    case info_flags::numeric:
+    case info_flags::polynomial:
+    case info_flags::rational_function:
+        return true;
+    case info_flags::real:
+        return is_real();
+    case info_flags::rational:
+    case info_flags::rational_polynomial:
+        return is_rational();
+    case info_flags::integer:
+    case info_flags::integer_polynomial:
+        return is_integer();
+    case info_flags::positive:
+        return is_positive();
+    case info_flags::negative:
+        return is_negative();
+    case info_flags::nonnegative:
+        return compare(numZERO())>=0;
+    case info_flags::posint:
+        return is_pos_integer();
+    case info_flags::negint:
+        return is_integer() && (compare(numZERO())<0);
+    case info_flags::nonnegint:
+        return is_nonneg_integer();
+    case info_flags::even:
+        return is_even();
+    case info_flags::odd:
+        return is_odd();
+    case info_flags::prime:
+        return is_prime();
+    }
+    return false;
+}
+
+/** Cast numeric into a floating-point object.  For example exact numeric(1) is
+ *  returned as a 1.0000000000000000000000 and so on according to how Digits is
+ *  currently set.
+ *
+ *  @param level  ignored, but needed for overriding basic::evalf.
+ *  @return an ex-handle to a numeric. */
+ex numeric::evalf(int level) const
+{
+    // level can safely be discarded for numeric objects.
+    return numeric(cl_float(1.0, cl_default_float_format) * (*value));  // -> CLN
+}
+
+// protected
+
+int numeric::compare_same_type(basic const & other) const
+{
+    ASSERT(is_exactly_of_type(other, numeric));
+    numeric const & o = static_cast<numeric &>(const_cast<basic &>(other));
+
+    if (*value == *o.value) {
+        return 0;
+    }
+
+    return compare(o);    
+}
+
+bool numeric::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_exactly_of_type(other,numeric));
+    numeric const *o = static_cast<numeric const *>(&other);
+    
+    return is_equal(*o);
+}
+
+/*
+unsigned numeric::calchash(void) const
+{
+    double d=to_double();
+    int s=d>0 ? 1 : -1;
+    d=fabs(d);
+    if (d>0x07FF0000) {
+        d=0x07FF0000;
+    }
+    return 0x88000000U+s*unsigned(d/0x07FF0000);
+}
+*/
+
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+
+/** Numerical addition method.  Adds argument to *this and returns result as
+ *  a new numeric object. */
+numeric numeric::add(numeric const & other) const
+{
+    return numeric((*value)+(*other.value));
+}
+
+/** Numerical subtraction method.  Subtracts argument from *this and returns
+ *  result as a new numeric object. */
+numeric numeric::sub(numeric const & other) const
+{
+    return numeric((*value)-(*other.value));
+}
+
+/** Numerical multiplication method.  Multiplies *this and argument and returns
+ *  result as a new numeric object. */
+numeric numeric::mul(numeric const & other) const
+{
+    static const numeric * numONEp=&numONE();
+    if (this==numONEp) {
+        return other;
+    } else if (&other==numONEp) {
+        return *this;
+    }
+    return numeric((*value)*(*other.value));
+}
+
+/** Numerical division method.  Divides *this by argument and returns result as
+ *  a new numeric object.
+ *
+ *  @exception overflow_error (division by zero) */
+numeric numeric::div(numeric const & other) const
+{
+    if (zerop(*other.value))
+        throw (std::overflow_error("division by zero"));
+    return numeric((*value)/(*other.value));
+}
+
+numeric numeric::power(numeric const & other) const
+{
+    static const numeric * numONEp=&numONE();
+    if (&other==numONEp) {
+        return *this;
+    }
+    if (zerop(*value) && other.is_real() && minusp(realpart(*other.value)))
+        throw (std::overflow_error("division by zero"));
+    return numeric(expt(*value,*other.value));
+}
+
+/** Inverse of a number. */
+numeric numeric::inverse(void) const
+{
+    return numeric(recip(*value));  // -> CLN
+}
+
+numeric const & numeric::add_dyn(numeric const & other) const
+{
+    return static_cast<numeric const &>((new numeric((*value)+(*other.value)))->
+                                        setflag(status_flags::dynallocated));
+}
+
+numeric const & numeric::sub_dyn(numeric const & other) const
+{
+    return static_cast<numeric const &>((new numeric((*value)-(*other.value)))->
+                                        setflag(status_flags::dynallocated));
+}
+
+numeric const & numeric::mul_dyn(numeric const & other) const
+{
+    static const numeric * numONEp=&numONE();
+    if (this==numONEp) {
+        return other;
+    } else if (&other==numONEp) {
+        return *this;
+    }
+    return static_cast<numeric const &>((new numeric((*value)*(*other.value)))->
+                                        setflag(status_flags::dynallocated));
+}
+
+numeric const & numeric::div_dyn(numeric const & other) const
+{
+    if (zerop(*other.value))
+        throw (std::overflow_error("division by zero"));
+    return static_cast<numeric const &>((new numeric((*value)/(*other.value)))->
+                                        setflag(status_flags::dynallocated));
+}
+
+numeric const & numeric::power_dyn(numeric const & other) const
+{
+    static const numeric * numONEp=&numONE();
+    if (&other==numONEp) {
+        return *this;
+    }
+    // The ifs are only a workaround for a bug in CLN. It gets stuck otherwise:
+    if ( !other.is_integer() &&
+         other.is_rational() &&
+         (*this).is_nonneg_integer() ) {
+        if ( !zerop(*value) ) {
+            return static_cast<numeric const &>((new numeric(exp(*other.value * log(*value))))->
+                                                setflag(status_flags::dynallocated));
+        } else {
+            if ( !zerop(*other.value) ) {  // 0^(n/m)
+                return static_cast<numeric const &>((new numeric(0))->
+                                                    setflag(status_flags::dynallocated));
+            } else {                       // raise FPE (0^0 requested)
+                return static_cast<numeric const &>((new numeric(1/(*other.value)))->
+                                                    setflag(status_flags::dynallocated));
+            }
+        }
+    } else {                               // default -> CLN
+        return static_cast<numeric const &>((new numeric(expt(*value,*other.value)))->
+                                            setflag(status_flags::dynallocated));
+    }
+}
+
+numeric const & numeric::operator=(int i)
+{
+    return operator=(numeric(i));
+}
+
+numeric const & numeric::operator=(unsigned int i)
+{
+    return operator=(numeric(i));
+}
+
+numeric const & numeric::operator=(long i)
+{
+    return operator=(numeric(i));
+}
+
+numeric const & numeric::operator=(unsigned long i)
+{
+    return operator=(numeric(i));
+}
+
+numeric const & numeric::operator=(double d)
+{
+    return operator=(numeric(d));
+}
+
+numeric const & numeric::operator=(char const * s)
+{
+    return operator=(numeric(s));
+}
+
+/** This method establishes a canonical order on all numbers.  For complex
+ *  numbers this is not possible in a mathematically consistent way but we need
+ *  to establish some order and it ought to be fast.  So we simply define it
+ *  similar to Maple's csgn. */
+int numeric::compare(numeric const & other) const
+{
+    // Comparing two real numbers?
+    if (is_real() && other.is_real())
+        // Yes, just compare them
+        return cl_compare(The(cl_R)(*value), The(cl_R)(*other.value));    
+    else {
+        // No, first compare real parts
+        cl_signean real_cmp = cl_compare(realpart(*value), realpart(*other.value));
+        if (real_cmp)
+            return real_cmp;
+
+        return cl_compare(imagpart(*value), imagpart(*other.value));
+    }
+}
+
+bool numeric::is_equal(numeric const & other) const
+{
+    return (*value == *other.value);
+}
+
+/** True if object is zero. */
+bool numeric::is_zero(void) const
+{
+    return zerop(*value);  // -> CLN
+}
+
+/** True if object is not complex and greater than zero. */
+bool numeric::is_positive(void) const
+{
+    if (is_real()) {
+        return plusp(The(cl_R)(*value));  // -> CLN
+    }
+    return false;
+}
+
+/** True if object is not complex and less than zero. */
+bool numeric::is_negative(void) const
+{
+    if (is_real()) {
+        return minusp(The(cl_R)(*value));  // -> CLN
+    }
+    return false;
+}
+
+/** True if object is a non-complex integer. */
+bool numeric::is_integer(void) const
+{
+    return (bool)instanceof(*value, cl_I_ring);  // -> CLN
+}
+
+/** True if object is an exact integer greater than zero. */
+bool numeric::is_pos_integer(void) const
+{
+    return (is_integer() &&
+            plusp(The(cl_I)(*value)));  // -> CLN
+}
+
+/** True if object is an exact integer greater or equal zero. */
+bool numeric::is_nonneg_integer(void) const
+{
+    return (is_integer() &&
+            !minusp(The(cl_I)(*value)));  // -> CLN
+}
+
+/** True if object is an exact even integer. */
+bool numeric::is_even(void) const
+{
+    return (is_integer() &&
+            evenp(The(cl_I)(*value)));  // -> CLN
+}
+
+/** True if object is an exact odd integer. */
+bool numeric::is_odd(void) const
+{
+    return (is_integer() &&
+            oddp(The(cl_I)(*value)));  // -> CLN
+}
+
+/** Probabilistic primality test.
+ *
+ *  @return  true if object is exact integer and prime. */
+bool numeric::is_prime(void) const
+{
+    return (is_integer() &&
+            isprobprime(The(cl_I)(*value)));  // -> CLN
+}
+
+/** True if object is an exact rational number, may even be complex
+ *  (denominator may be unity). */
+bool numeric::is_rational(void) const
+{
+    if (instanceof(*value, cl_RA_ring)) {
+        return true;
+    } else if (!is_real()) {  // complex case, handle Q(i):
+        if ( instanceof(realpart(*value), cl_RA_ring) &&
+             instanceof(imagpart(*value), cl_RA_ring) )
+            return true;
+    }
+    return false;
+}
+
+/** True if object is a real integer, rational or float (but not complex). */
+bool numeric::is_real(void) const
+{
+    return (bool)instanceof(*value, cl_R_ring);  // -> CLN
+}
+
+bool numeric::operator==(numeric const & other) const
+{
+    return (*value == *other.value);  // -> CLN
+}
+
+bool numeric::operator!=(numeric const & other) const
+{
+    return (*value != *other.value);  // -> CLN
+}
+
+/** Numerical comparison: less.
+ *
+ *  @exception invalid_argument (complex inequality) */ 
+bool numeric::operator<(numeric const & other) const
+{
+    if ( is_real() && other.is_real() ) {
+        return (bool)(The(cl_R)(*value) < The(cl_R)(*other.value));  // -> CLN
+    }
+    throw (std::invalid_argument("numeric::operator<(): complex inequality"));
+    return false;  // make compiler shut up
+}
+
+/** Numerical comparison: less or equal.
+ *
+ *  @exception invalid_argument (complex inequality) */ 
+bool numeric::operator<=(numeric const & other) const
+{
+    if ( is_real() && other.is_real() ) {
+        return (bool)(The(cl_R)(*value) <= The(cl_R)(*other.value));  // -> CLN
+    }
+    throw (std::invalid_argument("numeric::operator<=(): complex inequality"));
+    return false;  // make compiler shut up
+}
+
+/** Numerical comparison: greater.
+ *
+ *  @exception invalid_argument (complex inequality) */ 
+bool numeric::operator>(numeric const & other) const
+{
+    if ( is_real() && other.is_real() ) {
+        return (bool)(The(cl_R)(*value) > The(cl_R)(*other.value));  // -> CLN
+    }
+    throw (std::invalid_argument("numeric::operator>(): complex inequality"));
+    return false;  // make compiler shut up
+}
+
+/** Numerical comparison: greater or equal.
+ *
+ *  @exception invalid_argument (complex inequality) */  
+bool numeric::operator>=(numeric const & other) const
+{
+    if ( is_real() && other.is_real() ) {
+        return (bool)(The(cl_R)(*value) >= The(cl_R)(*other.value));  // -> CLN
+    }
+    throw (std::invalid_argument("numeric::operator>=(): complex inequality"));
+    return false;  // make compiler shut up
+}
+
+/** Converts numeric types to machine's int. You should check with is_integer()
+ *  if the number is really an integer before calling this method. */
+int numeric::to_int(void) const
+{
+    ASSERT(is_integer());
+    return cl_I_to_int(The(cl_I)(*value));
+}
+
+/** Converts numeric types to machine's double. You should check with is_real()
+ *  if the number is really not complex before calling this method. */
+double numeric::to_double(void) const
+{
+    ASSERT(is_real());
+    return cl_double_approx(realpart(*value));
+}
+
+/** Real part of a number. */
+numeric numeric::real(void) const
+{
+    return numeric(realpart(*value));  // -> CLN
+}
+
+/** Imaginary part of a number. */
+numeric numeric::imag(void) const
+{
+    return numeric(imagpart(*value));  // -> CLN
+}
+
+#ifndef SANE_LINKER
+// Unfortunately, CLN did not provide an official way to access the numerator
+// or denominator of a rational number (cl_RA). Doing some excavations in CLN
+// one finds how it works internally in src/rational/cl_RA.h:
+struct cl_heap_ratio : cl_heap {
+    cl_I numerator;
+    cl_I denominator;
+};
+
+inline cl_heap_ratio* TheRatio (const cl_N& obj)
+{ return (cl_heap_ratio*)(obj.pointer); }
+#endif // ndef SANE_LINKER
+
+/** Numerator.  Computes the numerator of rational numbers, rationalized
+ *  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 itself in all other cases. */
+numeric numeric::numer(void) const
+{
+    if (is_integer()) {
+        return numeric(*this);
+    }
+#ifdef SANE_LINKER
+    else if (instanceof(*value, cl_RA_ring)) {
+        return numeric(numerator(The(cl_RA)(*value)));
+    }
+    else if (!is_real()) {  // complex case, handle Q(i):
+        cl_R r = realpart(*value);
+        cl_R i = imagpart(*value);
+        if (instanceof(r, cl_I_ring) && instanceof(i, cl_I_ring))
+            return numeric(*this);
+        if (instanceof(r, cl_I_ring) && instanceof(i, cl_RA_ring))
+            return numeric(complex(r*denominator(The(cl_RA)(i)), numerator(The(cl_RA)(i))));
+        if (instanceof(r, cl_RA_ring) && instanceof(i, cl_I_ring))
+            return numeric(complex(numerator(The(cl_RA)(r)), i*denominator(The(cl_RA)(r))));
+        if (instanceof(r, cl_RA_ring) && instanceof(i, cl_RA_ring)) {
+            cl_I s = lcm(denominator(The(cl_RA)(r)), denominator(The(cl_RA)(i)));
+            return numeric(complex(numerator(The(cl_RA)(r))*(exquo(s,denominator(The(cl_RA)(r)))),
+                                   numerator(The(cl_RA)(i))*(exquo(s,denominator(The(cl_RA)(i))))));
+        }
+    }
+#else
+    else if (instanceof(*value, cl_RA_ring)) {
+        return numeric(TheRatio(*value)->numerator);
+    }
+    else if (!is_real()) {  // complex case, handle Q(i):
+        cl_R r = realpart(*value);
+        cl_R i = imagpart(*value);
+        if (instanceof(r, cl_I_ring) && instanceof(i, cl_I_ring))
+            return numeric(*this);
+        if (instanceof(r, cl_I_ring) && instanceof(i, cl_RA_ring))
+            return numeric(complex(r*TheRatio(i)->denominator, TheRatio(i)->numerator));
+        if (instanceof(r, cl_RA_ring) && instanceof(i, cl_I_ring))
+            return numeric(complex(TheRatio(r)->numerator, i*TheRatio(r)->denominator));
+        if (instanceof(r, cl_RA_ring) && instanceof(i, cl_RA_ring)) {
+            cl_I s = lcm(TheRatio(r)->denominator, TheRatio(i)->denominator);
+            return numeric(complex(TheRatio(r)->numerator*(exquo(s,TheRatio(r)->denominator)),
+                                   TheRatio(i)->numerator*(exquo(s,TheRatio(i)->denominator))));
+        }
+    }
+#endif // def SANE_LINKER
+    // at least one float encountered
+    return numeric(*this);
+}
+
+/** 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. */
+numeric numeric::denom(void) const
+{
+    if (is_integer()) {
+        return numONE();
+    }
+#ifdef SANE_LINKER
+    if (instanceof(*value, cl_RA_ring)) {
+        return numeric(denominator(The(cl_RA)(*value)));
+    }
+    if (!is_real()) {  // complex case, handle Q(i):
+        cl_R r = realpart(*value);
+        cl_R i = imagpart(*value);
+        if (instanceof(r, cl_I_ring) && instanceof(i, cl_I_ring))
+            return numONE();
+        if (instanceof(r, cl_I_ring) && instanceof(i, cl_RA_ring))
+            return numeric(denominator(The(cl_RA)(i)));
+        if (instanceof(r, cl_RA_ring) && instanceof(i, cl_I_ring))
+            return numeric(denominator(The(cl_RA)(r)));
+        if (instanceof(r, cl_RA_ring) && instanceof(i, cl_RA_ring))
+            return numeric(lcm(denominator(The(cl_RA)(r)), denominator(The(cl_RA)(i))));
+    }
+#else
+    if (instanceof(*value, cl_RA_ring)) {
+        return numeric(TheRatio(*value)->denominator);
+    }
+    if (!is_real()) {  // complex case, handle Q(i):
+        cl_R r = realpart(*value);
+        cl_R i = imagpart(*value);
+        if (instanceof(r, cl_I_ring) && instanceof(i, cl_I_ring))
+            return numONE();
+        if (instanceof(r, cl_I_ring) && instanceof(i, cl_RA_ring))
+            return numeric(TheRatio(i)->denominator);
+        if (instanceof(r, cl_RA_ring) && instanceof(i, cl_I_ring))
+            return numeric(TheRatio(r)->denominator);
+        if (instanceof(r, cl_RA_ring) && instanceof(i, cl_RA_ring))
+            return numeric(lcm(TheRatio(r)->denominator, TheRatio(i)->denominator));
+    }
+#endif // def SANE_LINKER
+    // at least one float encountered
+    return numONE();
+}
+
+/** Size in binary notation.  For integers, this is the smallest n >= 0 such
+ *  that -2^n <= x < 2^n. If x > 0, this is the unique n > 0 such that
+ *  2^(n-1) <= x < 2^n.
+ *
+ *  @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
+{
+    if (is_integer()) {
+        return integer_length(The(cl_I)(*value));  // -> CLN
+    } else {
+        return 0;
+    }
+}
+
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned numeric::precedence = 30;
+
+//////////
+// global constants
+//////////
+
+const numeric some_numeric;
+type_info const & typeid_numeric=typeid(some_numeric);
+/** Imaginary unit.  This is not a constant but a numeric since we are
+ *  natively handing complex numbers anyways. */
+const numeric I = (complex(cl_I(0),cl_I(1)));
+
+//////////
+// global functions
+//////////
+
+numeric const & numZERO(void)
+{
+    const static ex eZERO = ex((new numeric(0))->setflag(status_flags::dynallocated));
+    const static numeric * nZERO = static_cast<const numeric *>(eZERO.bp);
+    return *nZERO;
+}
+
+numeric const & numONE(void)
+{
+    const static ex eONE = ex((new numeric(1))->setflag(status_flags::dynallocated));
+    const static numeric * nONE = static_cast<const numeric *>(eONE.bp);
+    return *nONE;
+}
+
+numeric const & numTWO(void)
+{
+    const static ex eTWO = ex((new numeric(2))->setflag(status_flags::dynallocated));
+    const static numeric * nTWO = static_cast<const numeric *>(eTWO.bp);
+    return *nTWO;
+}
+
+numeric const & numTHREE(void)
+{
+    const static ex eTHREE = ex((new numeric(3))->setflag(status_flags::dynallocated));
+    const static numeric * nTHREE = static_cast<const numeric *>(eTHREE.bp);
+    return *nTHREE;
+}
+
+numeric const & numMINUSONE(void)
+{
+    const static ex eMINUSONE = ex((new numeric(-1))->setflag(status_flags::dynallocated));
+    const static numeric * nMINUSONE = static_cast<const numeric *>(eMINUSONE.bp);
+    return *nMINUSONE;
+}
+
+numeric const & numHALF(void)
+{
+    const static ex eHALF = ex((new numeric(1, 2))->setflag(status_flags::dynallocated));
+    const static numeric * nHALF = static_cast<const numeric *>(eHALF.bp);
+    return *nHALF;
+}
+
+/** Exponential function.
+ *
+ *  @return  arbitrary precision numerical exp(x). */
+numeric exp(numeric const & x)
+{
+    return exp(*x.value);  // -> CLN
+}
+
+/** Natural logarithm.
+ *
+ *  @param z complex number
+ *  @return  arbitrary precision numerical log(x).
+ *  @exception overflow_error (logarithmic singularity) */
+numeric log(numeric const & z)
+{
+    if (z.is_zero())
+        throw (std::overflow_error("log(): logarithmic singularity"));
+    return log(*z.value);  // -> CLN
+}
+
+/** Numeric sine (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical sin(x). */
+numeric sin(numeric const & x)
+{
+    return sin(*x.value);  // -> CLN
+}
+
+/** Numeric cosine (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical cos(x). */
+numeric cos(numeric const & x)
+{
+    return cos(*x.value);  // -> CLN
+}
+    
+/** Numeric tangent (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical tan(x). */
+numeric tan(numeric const & x)
+{
+    return tan(*x.value);  // -> CLN
+}
+    
+/** Numeric inverse sine (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical asin(x). */
+numeric asin(numeric const & x)
+{
+    return asin(*x.value);  // -> CLN
+}
+    
+/** Numeric inverse cosine (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical acos(x). */
+numeric acos(numeric const & x)
+{
+    return acos(*x.value);  // -> CLN
+}
+    
+/** Arcustangents.
+ *
+ *  @param z complex number
+ *  @return atan(z)
+ *  @exception overflow_error (logarithmic singularity) */
+numeric atan(numeric const & x)
+{
+    if (!x.is_real() &&
+        x.real().is_zero() &&
+        !abs(x.imag()).is_equal(numONE()))
+        throw (std::overflow_error("atan(): logarithmic singularity"));
+    return atan(*x.value);  // -> CLN
+}
+
+/** Arcustangents.
+ *
+ *  @param x real number
+ *  @param y real number
+ *  @return atan(y/x) */
+numeric atan(numeric const & y, numeric const & x)
+{
+    if (x.is_real() && y.is_real())
+        return atan(realpart(*x.value), realpart(*y.value));  // -> CLN
+    else
+        throw (std::invalid_argument("numeric::atan(): complex argument"));        
+}
+
+/** Numeric hyperbolic sine (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical sinh(x). */
+numeric sinh(numeric const & x)
+{
+    return sinh(*x.value);  // -> CLN
+}
+
+/** Numeric hyperbolic cosine (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical cosh(x). */
+numeric cosh(numeric const & x)
+{
+    return cosh(*x.value);  // -> CLN
+}
+    
+/** Numeric hyperbolic tangent (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical tanh(x). */
+numeric tanh(numeric const & x)
+{
+    return tanh(*x.value);  // -> CLN
+}
+    
+/** Numeric inverse hyperbolic sine (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical asinh(x). */
+numeric asinh(numeric const & x)
+{
+    return asinh(*x.value);  // -> CLN
+}
+
+/** Numeric inverse hyperbolic cosine (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical acosh(x). */
+numeric acosh(numeric const & x)
+{
+    return acosh(*x.value);  // -> CLN
+}
+
+/** Numeric inverse hyperbolic tangent (trigonometric function).
+ *
+ *  @return  arbitrary precision numerical atanh(x). */
+numeric atanh(numeric const & x)
+{
+    return atanh(*x.value);  // -> CLN
+}
+
+/** The gamma function.
+ *  stub stub stub stub stub stub! */
+numeric gamma(numeric const & x)
+{
+    clog << "gamma(): Nobody expects the Spanish inquisition" << endl;
+    return numeric(0);
+}
+
+/** Factorial combinatorial function.
+ *
+ *  @exception range_error (argument must be integer >= 0) */
+numeric factorial(numeric const & nn)
+{
+    if ( !nn.is_nonneg_integer() ) {
+        throw (std::range_error("numeric::factorial(): argument must be integer >= 0"));
+    }
+    
+    return numeric(factorial(nn.to_int()));  // -> CLN
+}
+
+/** The double factorial combinatorial function.  (Scarcely used, but still
+ *  useful in cases, like for exact results of Gamma(n+1/2) for instance.)
+ *
+ *  @param n  integer argument >= -1
+ *  @return n!! == n * (n-2) * (n-4) * ... * ({1|2}) with 0!! == 1 == (-1)!!
+ *  @exception range_error (argument must be integer >= -1) */
+numeric doublefactorial(numeric const & nn)
+{
+    // We store the results separately for even and odd arguments.  This has
+    // the advantage that we don't have to compute any even result at all if
+    // the function is always called with odd arguments and vice versa.  There
+    // is no tradeoff involved in this, it is guaranteed to save time as well
+    // as memory.  (If this is not enough justification consider the Gamma
+    // function of half integer arguments: it only needs odd doublefactorials.)
+    static vector<numeric> evenresults;
+    static int highest_evenresult = -1;
+    static vector<numeric> oddresults;
+    static int highest_oddresult = -1;
+    
+    if ( nn == numeric(-1) ) {
+        return numONE();
+    }
+    if ( !nn.is_nonneg_integer() ) {
+        throw (std::range_error("numeric::doublefactorial(): argument must be integer >= -1"));
+    }
+    if ( nn.is_even() ) {
+        int n = nn.div(numTWO()).to_int();
+        if ( n <= highest_evenresult ) {
+            return evenresults[n];
+        }
+        if ( evenresults.capacity() < (unsigned)(n+1) ) {
+            evenresults.reserve(n+1);
+        }
+        if ( highest_evenresult < 0 ) {
+            evenresults.push_back(numONE());
+            highest_evenresult=0;
+        }
+        for (int i=highest_evenresult+1; i<=n; i++) {
+            evenresults.push_back(numeric(evenresults[i-1].mul(numeric(i*2))));
+        }
+        highest_evenresult=n;
+        return evenresults[n];
+    } else {
+        int n = nn.sub(numONE()).div(numTWO()).to_int();
+        if ( n <= highest_oddresult ) {
+            return oddresults[n];
+        }
+        if ( oddresults.capacity() < (unsigned)n ) {
+            oddresults.reserve(n+1);
+        }
+        if ( highest_oddresult < 0 ) {
+            oddresults.push_back(numONE());
+            highest_oddresult=0;
+        }
+        for (int i=highest_oddresult+1; i<=n; i++) {
+            oddresults.push_back(numeric(oddresults[i-1].mul(numeric(i*2+1))));
+        }
+        highest_oddresult=n;
+        return oddresults[n];
+    }
+}
+
+/** The Binomial function. It computes the binomial coefficients. If the
+ *  arguments are both nonnegative integers and 0 <= k <= n, then
+ *  binomial(n, k) = n!/k!/(n-k)! which is the number of ways of choosing k
+ *  objects from n distinct objects. If k > n, then binomial(n,k) returns 0. */
+numeric binomial(numeric const & n, numeric const & k)
+{
+    if (n.is_nonneg_integer() && k.is_nonneg_integer()) {
+        return numeric(binomial(n.to_int(),k.to_int()));  // -> CLN
+    } else {
+        // should really be gamma(n+1)/(gamma(r+1)/gamma(n-r+1)
+        return numeric(0);
+    }
+    // return factorial(n).div(factorial(k).mul(factorial(n.sub(k))));
+}
+
+/** Absolute value. */
+numeric abs(numeric const & x)
+{
+    return abs(*x.value);  // -> CLN
+}
+
+/** Modulus (in positive representation).
+ *  In general, mod(a,b) has the sign of b or is zero, and rem(a,b) has the
+ *  sign of a or is zero. This is different from Maple's modp, where the sign
+ *  of b is ignored. It is in agreement with Mathematica's Mod.
+ *
+ *  @return a mod b in the range [0,abs(b)-1] with sign of b if both are
+ *  integer, 0 otherwise. */
+numeric mod(numeric const & a, numeric const & b)
+{
+    if (a.is_integer() && b.is_integer()) {
+        return mod(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
+    }
+    else {
+        return numZERO();  // Throw?
+    }
+}
+
+/** Modulus (in symmetric representation).
+ *  Equivalent to Maple's mods.
+ *
+ *  @return a mod b in the range [-iquo(abs(m)-1,2), iquo(abs(m),2)]. */
+numeric smod(numeric const & a, numeric const & b)
+{
+    if (a.is_integer() && b.is_integer()) {
+        cl_I b2 = The(cl_I)(ceiling1(The(cl_I)(*b.value) / 2)) - 1;
+        return mod(The(cl_I)(*a.value) + b2, The(cl_I)(*b.value)) - b2;
+    } else {
+        return numZERO();  // Throw?
+    }
+}
+
+/** Numeric integer remainder.
+ *  Equivalent to Maple's irem(a,b) as far as sign conventions are concerned.
+ *  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.
+ *
+ *  @return remainder of a/b if both are integer, 0 otherwise. */
+numeric irem(numeric const & a, numeric const & b)
+{
+    if (a.is_integer() && b.is_integer()) {
+        return rem(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
+    }
+    else {
+        return numZERO();  // Throw?
+    }
+}
+
+/** 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.  
+ *
+ *  @return remainder of a/b and quotient stored in q if both are integer,
+ *  0 otherwise. */
+numeric irem(numeric const & a, numeric const & b, numeric & q)
+{
+    if (a.is_integer() && b.is_integer()) {  // -> CLN
+        cl_I_div_t rem_quo = truncate2(The(cl_I)(*a.value), The(cl_I)(*b.value));
+        q = rem_quo.quotient;
+        return rem_quo.remainder;
+    }
+    else {
+        q = numZERO();
+        return numZERO();  // Throw?
+    }
+}
+
+/** Numeric integer quotient.
+ *  Equivalent to Maple's iquo as far as sign conventions are concerned.
+ *  
+ *  @return truncated quotient of a/b if both are integer, 0 otherwise. */
+numeric iquo(numeric const & a, numeric const & b)
+{
+    if (a.is_integer() && b.is_integer()) {
+        return truncate1(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
+    } else {
+        return numZERO();  // Throw?
+    }
+}
+
+/** Numeric integer quotient.
+ *  Equivalent to Maple's iquo(a,b,'r') it obeyes the relation
+ *  r == a - iquo(a,b,r)*b.
+ *
+ *  @return truncated quotient of a/b and remainder stored in r if both are
+ *  integer, 0 otherwise. */
+numeric iquo(numeric const & a, numeric const & b, numeric & r)
+{
+    if (a.is_integer() && b.is_integer()) {  // -> CLN
+        cl_I_div_t rem_quo = truncate2(The(cl_I)(*a.value), The(cl_I)(*b.value));
+        r = rem_quo.remainder;
+        return rem_quo.quotient;
+    } else {
+        r = numZERO();
+        return numZERO();  // Throw?
+    }
+}
+
+/** Numeric square root.
+ *  If possible, sqrt(z) should respect squares of exact numbers, i.e. sqrt(4)
+ *  should return integer 2.
+ *
+ *  @param z numeric argument
+ *  @return square root of z. Branch cut along negative real axis, the negative
+ *  real axis itself where imag(z)==0 and real(z)<0 belongs to the upper part
+ *  where imag(z)>0. */
+numeric sqrt(numeric const & z)
+{
+    return sqrt(*z.value);  // -> CLN
+}
+
+/** Integer numeric square root. */
+numeric isqrt(numeric const & x)
+{
+       if (x.is_integer()) {
+               cl_I root;
+               isqrt(The(cl_I)(*x.value), &root);      // -> CLN
+               return root;
+       } else
+               return numZERO();  // Throw?
+}
+
+/** Greatest Common Divisor.
+ *   
+ *  @return  The GCD of two numbers if both are integer, a numerical 1
+ *  if they are not. */
+numeric gcd(numeric const & a, numeric const & b)
+{
+    if (a.is_integer() && b.is_integer())
+        return gcd(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
+    else
+        return numONE();
+}
+
+/** Least Common Multiple.
+ *   
+ *  @return  The LCM of two numbers if both are integer, the product of those
+ *  two numbers if they are not. */
+numeric lcm(numeric const & a, numeric const & b)
+{
+    if (a.is_integer() && b.is_integer())
+        return lcm(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
+    else
+        return *a.value * *b.value;
+}
+
+ex PiEvalf(void)
+{ 
+    return numeric(cl_pi(cl_default_float_format));  // -> CLN
+}
+
+ex EulerGammaEvalf(void)
+{ 
+    return numeric(cl_eulerconst(cl_default_float_format));  // -> CLN
+}
+
+ex CatalanEvalf(void)
+{
+    return numeric(cl_catalanconst(cl_default_float_format));  // -> CLN
+}
+
+// It initializes to 17 digits, because in CLN cl_float_format(17) turns out to
+// be 61 (<64) while cl_float_format(18)=65.  We want to have a cl_LF instead 
+// of cl_SF, cl_FF or cl_DF but everything else is basically arbitrary.
+_numeric_digits::_numeric_digits()
+    : digits(17)
+{
+    assert(!too_late);
+    too_late = true;
+    cl_default_float_format = cl_float_format(17); 
+}
+
+_numeric_digits& _numeric_digits::operator=(long prec)
+{
+    digits=prec;
+    cl_default_float_format = cl_float_format(prec); 
+    return *this;
+}
+
+_numeric_digits::operator long()
+{
+    return (long)digits;
+}
+
+void _numeric_digits::print(ostream & os) const
+{
+    debugmsg("_numeric_digits print", LOGLEVEL_PRINT);
+    os << digits;
+}
+
+ostream& operator<<(ostream& os, _numeric_digits const & e)
+{
+    e.print(os);
+    return os;
+}
+
+//////////
+// static member variables
+//////////
+
+// private
+
+bool _numeric_digits::too_late = false;
+
+/** Accuracy in decimal digits.  Only object of this type!  Can be set using
+ *  assignment from C++ unsigned ints and evaluated like any built-in type. */
+_numeric_digits Digits;
diff --git a/ginac/numeric.h b/ginac/numeric.h
new file mode 100644 (file)
index 0000000..0b2d28e
--- /dev/null
@@ -0,0 +1,307 @@
+/** @file numeric.h
+ *
+ *  Makes the interface to the underlying bignum package available. */
+
+#ifndef _NUMERIC_H_
+#define _NUMERIC_H_
+
+#include <strstream>
+
+#define HASHVALUE_NUMERIC 0x80000001U
+
+class numeric;  // Forward declaration, so basic doesn't argue...
+class cl_N;     // We want to include cln.h only in numeric.cpp in order to 
+                // avoid namespace pollution and keep compile-time low.
+#include "basic.h"
+
+/** This class is used to instantiate a global object Digits which
+ *  behaves just like Maple's Digits.  We need an object rather than a
+ *  dumber basic type since as a side-effect we let it change
+ *  cl_default_float_format when it gets changed.  The only other
+ *  meaningful thing to do with it is converting it to an unsigned,
+ *  for temprary storing its value e.g.  The user must not create an
+ *  own working object of this class!  Since C++ forces us to make the
+ *  class definition visible in order to use an object we put in a
+ *  flag which prevents other objects of that class to be created. */
+class _numeric_digits
+{
+// member functions
+public:
+    _numeric_digits();
+    _numeric_digits& operator=(long prec);
+    operator long();
+    void print(ostream & os) const;
+// member variables
+private:
+    long digits;
+    static bool too_late;
+};
+
+/** 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
+{
+// friends
+    friend numeric exp(numeric const & x);
+    friend numeric log(numeric const & x);
+    friend numeric sin(numeric const & x);
+    friend numeric cos(numeric const & x);
+    friend numeric tan(numeric const & x);
+    friend numeric asin(numeric const & x);
+    friend numeric acos(numeric const & x);
+    friend numeric atan(numeric const & x);
+    friend numeric atan(numeric const & y, numeric const & x);
+    friend numeric sinh(numeric const & x);
+    friend numeric cosh(numeric const & x);
+    friend numeric tanh(numeric const & x);
+    friend numeric asinh(numeric const & x);
+    friend numeric acosh(numeric const & x);
+    friend numeric atanh(numeric const & x);
+    friend numeric abs(numeric const & x);
+    friend numeric mod(numeric const & a, numeric const & b);
+    friend numeric smod(numeric const & a, numeric const & b);
+    friend numeric irem(numeric const & a, numeric const & b);
+    friend numeric irem(numeric const & a, numeric const & b, numeric & q);
+    friend numeric iquo(numeric const & a, numeric const & b);
+    friend numeric iquo(numeric const & a, numeric const & b, numeric & r);
+    friend numeric sqrt(numeric const & x);
+    friend numeric isqrt(numeric const & x);
+    friend numeric gcd(numeric const & a, numeric const & b);
+    friend numeric lcm(numeric const & a, numeric const & b);
+    friend numeric const & numZERO(void);
+    friend numeric const & numONE(void);
+    friend numeric const & numTWO(void);
+    friend numeric const & numTHREE(void);
+    friend numeric const & numMINUSONE(void);
+    friend numeric const & numHALF(void);
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment
+    // operator and helpers
+public:
+    numeric();
+    ~numeric();
+    numeric(numeric const & other);
+    numeric const & operator=(numeric const & other);
+protected:
+    void copy(numeric const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    explicit numeric(int i);
+    explicit numeric(unsigned int i);
+    explicit numeric(long i);
+    explicit numeric(unsigned long i);
+    explicit numeric(long numer, long denom);
+    explicit numeric(double d);
+    explicit numeric(char const *);
+    numeric(cl_N const & z);
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned precedence=0) const;
+    bool info(unsigned inf) const;
+    ex evalf(int level=0) const;
+    ex diff(symbol const & s) const;
+    ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+    numeric integer_content(void) const;
+    ex smod(numeric const &xi) const;
+    numeric max_coefficient(void) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned calchash(void) const {
+        hashvalue=HASHVALUE_NUMERIC;
+        return HASHVALUE_NUMERIC;
+    }
+
+    // new virtual functions which can be overridden by derived classes
+    // (none)
+
+    // non-virtual functions in this class
+public:
+    numeric add(numeric const & other) const;
+    numeric sub(numeric const & other) const;
+    numeric mul(numeric const & other) const;
+    numeric div(numeric const & other) const;
+    numeric power(numeric const & other) const;
+    numeric const & add_dyn(numeric const & other) const;
+    numeric const & sub_dyn(numeric const & other) const;
+    numeric const & mul_dyn(numeric const & other) const;
+    numeric const & div_dyn(numeric const & other) const;
+    numeric const & power_dyn(numeric const & other) const;
+    numeric const & operator=(int i);
+    numeric const & operator=(unsigned int i);
+    numeric const & operator=(long i);
+    numeric const & operator=(unsigned long i);
+    numeric const & operator=(double d);
+    numeric const & operator=(char const * s);
+    /*
+    numeric add_dyn(numeric const & other) const   { return add(other);   }
+    numeric sub_dyn(numeric const & other) const   { return sub(other);   }
+    numeric mul_dyn(numeric const & other) const   { return mul(other);   }
+    numeric div_dyn(numeric const & other) const   { return div(other);   }
+    numeric power_dyn(numeric const & other) const { return power(other); }
+    */
+    numeric inverse(void) const;
+    int compare(numeric const & other) const;
+    bool is_equal(numeric const & 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 operator==(numeric const & other) const;
+    bool operator!=(numeric const & other) const;
+    bool operator<(numeric const & other) const;
+    bool operator<=(numeric const & other) const;
+    bool operator>(numeric const & other) const;
+    bool operator>=(numeric const & other) const;
+    int to_int(void) const;
+    double to_double(void) const;
+    numeric real(void) const;
+    numeric imag(void) const;
+    numeric numer(void) const;
+    numeric denom(void) const;
+    int int_length(void) const;
+
+// member variables
+
+protected:
+    static unsigned precedence;
+    cl_N *value;
+};
+
+// global constants
+
+extern const numeric some_numeric;
+extern const numeric I;
+extern type_info const & typeid_numeric;
+extern _numeric_digits Digits;
+
+#define is_a_numeric_hash(x) ((x)==HASHVALUE_NUMERIC)
+// may have to be changed to ((x)>=0x80000000U)
+
+// global functions
+
+numeric const & numZERO(void);
+numeric const & numONE(void);
+numeric const & numTWO(void);
+numeric const & numMINUSONE(void);
+numeric const & numHALF(void);
+
+numeric exp(numeric const & x);
+numeric log(numeric const & x);
+numeric sin(numeric const & x);
+numeric cos(numeric const & x);
+numeric tan(numeric const & x);
+numeric asin(numeric const & x);
+numeric acos(numeric const & x);
+numeric atan(numeric const & x);
+numeric atan(numeric const & y, numeric const & x);
+numeric sinh(numeric const & x);
+numeric cosh(numeric const & x);
+numeric tanh(numeric const & x);
+numeric asinh(numeric const & x);
+numeric acosh(numeric const & x);
+numeric atanh(numeric const & x);
+numeric gamma(numeric const & x);
+numeric factorial(numeric const & n);
+numeric doublefactorial(numeric const & n);
+numeric binomial(numeric const & n, numeric const & k);
+
+numeric abs(numeric const & x);
+numeric mod(numeric const & a, numeric const & b);
+numeric smod(numeric const & a, numeric const & b);
+numeric irem(numeric const & a, numeric const & b);
+numeric irem(numeric const & a, numeric const & b, numeric & q);
+numeric iquo(numeric const & a, numeric const & b);
+numeric iquo(numeric const & a, numeric const & b, numeric & r);
+numeric sqrt(numeric const & x);
+numeric isqrt(numeric const & x);
+
+numeric gcd(numeric const & a, numeric const & b);
+numeric lcm(numeric const & a, numeric const & b);
+
+/** Exception thrown by numeric members to signal failure */
+struct numeric_fail
+{
+    int failval;
+    numeric_fail(int n) { failval = n; }
+};
+
+// wrapper functions around member functions
+inline numeric inverse(numeric const & x)
+{ return x.inverse(); }
+
+inline bool is_zero(numeric const & x)
+{ return x.is_zero(); }
+
+inline bool is_positive(numeric const & x)
+{ return x.is_positive(); }
+
+inline bool is_integer(numeric const & x)
+{ return x.is_integer(); }
+
+inline bool is_pos_integer(numeric const & x)
+{ return x.is_pos_integer(); }
+
+inline bool is_nonneg_integer(numeric const & x)
+{ return x.is_nonneg_integer(); }
+
+inline bool is_even(numeric const & x)
+{ return x.is_even(); }
+
+inline bool is_odd(numeric const & x)
+{ return x.is_odd(); }
+
+inline bool is_prime(numeric const & x)
+{ return x.is_prime(); }
+
+inline bool is_rational(numeric const & x)
+{ return x.is_rational(); }
+
+inline bool is_real(numeric const & x)
+{ return x.is_real(); }
+
+inline numeric real(numeric const & x)
+{ return x.real(); }
+
+inline numeric imag(numeric const & x)
+{ return x.imag(); }
+
+inline numeric numer(numeric const & x)
+{ return x.numer(); }
+
+inline numeric denom(numeric const & x)
+{ return x.denom(); }
+
+/* do we need this any more? */
+//inline numeric factorial(int n)
+//{ return factorial(numeric(n)); }
+
+/* do we need this any more? */
+//inline numeric binomial(int n, int k)
+//{ return binomial(numeric(n), numeric(k)); }
+
+ex IEvalf(void);
+ex PiEvalf(void);
+ex EulerGammaEvalf(void);
+ex CatalanEvalf(void);
+
+#define ex_to_numeric(X) static_cast<numeric const &>(*(X).bp)
+
+
+#endif // ndef _NUMERIC_H_
diff --git a/ginac/operators.cpp b/ginac/operators.cpp
new file mode 100644 (file)
index 0000000..abd5061
--- /dev/null
@@ -0,0 +1,382 @@
+/** @file operators.cpp
+ *
+ *  Implementation of GiNaC's overloaded operators. */
+
+#include <iostream>
+#include <stdexcept>
+
+#include "ginac.h"
+
+// binary arithmetic operators ex with ex
+
+ex operator+(ex const & lh, ex const & rh)
+{
+    debugmsg("operator+(ex,ex)",LOGLEVEL_OPERATOR);
+    return lh.exadd(rh);
+}
+
+ex operator-(ex const & lh, ex const & rh)
+{
+    debugmsg("operator-(ex,ex)",LOGLEVEL_OPERATOR);
+    return lh.exadd(rh.exmul(exMINUSONE()));
+}
+
+ex operator*(ex const & lh, ex const & rh)
+{
+    debugmsg("operator*(ex,ex)",LOGLEVEL_OPERATOR);
+    return lh.exmul(rh);
+}
+
+ex operator/(ex const & lh, ex const & rh)
+{
+    debugmsg("operator*(ex,ex)",LOGLEVEL_OPERATOR);
+    return lh.exmul(power(rh,exMINUSONE()));
+}
+
+ex operator%(ex const & lh, ex const & rh)
+{
+    debugmsg("operator%(ex,ex)",LOGLEVEL_OPERATOR);
+    return lh.exncmul(rh);
+}
+
+/*
+
+// binary arithmetic operators ex with numeric
+
+ex operator+(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator+(ex,numeric)",LOGLEVEL_OPERATOR);
+    return lh+ex(rh);
+}
+
+ex operator-(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator-(ex,numeric)",LOGLEVEL_OPERATOR);
+    return lh-ex(rh);
+}
+
+ex operator*(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator*(ex,numeric)",LOGLEVEL_OPERATOR);
+    return lh*ex(rh);
+}
+
+ex operator/(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator/(ex,numeric)",LOGLEVEL_OPERATOR);
+    return lh/ex(rh);
+}
+
+ex operator%(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator%(ex,numeric)",LOGLEVEL_OPERATOR);
+    return lh%ex(rh);
+}
+
+// binary arithmetic operators numeric with ex
+
+ex operator+(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator+(numeric,ex)",LOGLEVEL_OPERATOR);
+    return ex(lh)+rh;
+}
+
+ex operator-(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator-(numeric,ex)",LOGLEVEL_OPERATOR);
+    return ex(lh)-rh;
+}
+
+ex operator*(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator*(numeric,ex)",LOGLEVEL_OPERATOR);
+    return ex(lh)*rh;
+}
+
+ex operator/(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator/(numeric,ex)",LOGLEVEL_OPERATOR);
+    return ex(lh)/rh;
+}
+
+ex operator%(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator%(numeric,ex)",LOGLEVEL_OPERATOR);
+    return ex(lh)%rh;
+}
+
+*/
+
+// binary arithmetic operators numeric with numeric
+
+numeric operator+(numeric const & lh, numeric const & rh)
+{
+    debugmsg("operator+(numeric,numeric)",LOGLEVEL_OPERATOR);
+    return lh.add(rh);
+}
+
+numeric operator-(numeric const & lh, numeric const & rh)
+{
+    debugmsg("operator-(numeric,numeric)",LOGLEVEL_OPERATOR);
+    return lh.sub(rh);
+}
+
+numeric operator*(numeric const & lh, numeric const & rh)
+{
+    debugmsg("operator*(numeric,numeric)",LOGLEVEL_OPERATOR);
+    return lh.mul(rh);
+}
+
+numeric operator/(numeric const & lh, numeric const & rh)
+{
+    debugmsg("operator/(numeric,ex)",LOGLEVEL_OPERATOR);
+    return lh.div(rh);
+}
+
+// binary arithmetic assignment operators with ex
+
+ex const & operator+=(ex & lh, ex const & rh)
+{
+    debugmsg("operator+=(ex,ex)",LOGLEVEL_OPERATOR);
+    return (lh=lh+rh);
+}
+
+ex const & operator-=(ex & lh, ex const & rh)
+{
+    debugmsg("operator-=(ex,ex)",LOGLEVEL_OPERATOR);
+    return (lh=lh-rh);
+}
+
+ex const & operator*=(ex & lh, ex const & rh)
+{
+    debugmsg("operator*=(ex,ex)",LOGLEVEL_OPERATOR);
+    return (lh=lh*rh);
+}
+
+ex const & operator/=(ex & lh, ex const & rh)
+{
+    debugmsg("operator/=(ex,ex)",LOGLEVEL_OPERATOR);
+    return (lh=lh/rh);
+}
+
+ex const & operator%=(ex & lh, ex const & rh)
+{
+    debugmsg("operator%=(ex,ex)",LOGLEVEL_OPERATOR);
+    return (lh=lh%rh);
+}
+
+/*
+
+// binary arithmetic assignment operators with numeric
+
+ex const & operator+=(ex & lh, numeric const & rh)
+{
+    debugmsg("operator+=(ex,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh+ex(rh));
+}
+
+ex const & operator-=(ex & lh, numeric const & rh)
+{
+    debugmsg("operator-=(ex,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh-ex(rh));
+}
+
+ex const & operator*=(ex & lh, numeric const & rh)
+{
+    debugmsg("operator*=(ex,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh*ex(rh));
+}
+
+ex const & operator/=(ex & lh, numeric const & rh)
+{
+    debugmsg("operator/=(ex,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh/ex(rh));
+}
+
+ex const & operator%=(ex & lh, numeric const & rh)
+{
+    debugmsg("operator%=(ex,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh%ex(rh));
+}
+
+*/
+
+// binary arithmetic assignment operators with numeric
+
+numeric const & operator+=(numeric & lh, numeric const & rh)
+{
+    debugmsg("operator+=(numeric,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh.add(rh));
+}
+
+numeric const & operator-=(numeric & lh, numeric const & rh)
+{
+    debugmsg("operator-=(numeric,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh.sub(rh));
+}
+
+numeric const & operator*=(numeric & lh, numeric const & rh)
+{
+    debugmsg("operator*=(numeric,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh.mul(rh));
+}
+
+numeric const & operator/=(numeric & lh, numeric const & rh)
+{
+    debugmsg("operator/=(numeric,numeric)",LOGLEVEL_OPERATOR);
+    return (lh=lh.div(rh));
+}
+
+// unary operators
+
+ex operator+(ex const & lh)
+{
+    return lh;
+}
+
+ex operator-(ex const & lh)
+{
+    return exMINUSONE()*lh;
+}
+
+numeric operator+(numeric const & lh)
+{
+    return lh;
+}
+
+numeric operator-(numeric const & lh)
+{
+    return (numeric(-1)*lh);
+}
+
+// binary relational operators ex with ex
+
+relational operator==(ex const & lh, ex const & rh)
+{
+    debugmsg("operator==(ex,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::equal);
+}
+
+relational operator!=(ex const & lh, ex const & rh)
+{
+    debugmsg("operator!=(ex,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::not_equal);
+}
+
+relational operator<(ex const & lh, ex const & rh)
+{
+    debugmsg("operator<(ex,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::less);
+}
+
+relational operator<=(ex const & lh, ex const & rh)
+{
+    debugmsg("operator<=(ex,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::less_or_equal);
+}
+
+relational operator>(ex const & lh, ex const & rh)
+{
+    debugmsg("operator>(ex,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::greater);
+}
+
+relational operator>=(ex const & lh, ex const & rh)
+{
+    debugmsg("operator>=(ex,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::greater_or_equal);
+}
+
+/*
+
+// binary relational operators ex with numeric
+
+relational operator==(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator==(ex,numeric)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::equal);
+}
+
+relational operator!=(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator!=(ex,numeric)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::not_equal);
+}
+
+relational operator<(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator<(ex,numeric)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::less);
+}
+
+relational operator<=(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator<=(ex,numeric)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::less_or_equal);
+}
+
+relational operator>(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator>(ex,numeric)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::greater);
+}
+
+relational operator>=(ex const & lh, numeric const & rh)
+{
+    debugmsg("operator>=(ex,numeric)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::greater_or_equal);
+}
+
+// binary relational operators numeric with ex
+
+relational operator==(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator==(numeric,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::equal);
+}
+
+relational operator!=(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator!=(numeric,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::not_equal);
+}
+
+relational operator<(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator<(numeric,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::less);
+}
+
+relational operator<=(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator<=(numeric,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::less_or_equal);
+}
+
+relational operator>(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator>(numeric,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::greater);
+}
+
+relational operator>=(numeric const & lh, ex const & rh)
+{
+    debugmsg("operator>=(numeric,ex)",LOGLEVEL_OPERATOR);
+    return relational(lh,rh,relational::greater_or_equal);
+}
+
+*/
+
+// input/output stream operators
+
+ostream & operator<<(ostream & os, ex const & e)
+{
+    e.print(os);
+    return os;
+}
+
+istream & operator>>(istream & is, ex & e)
+{
+    throw(std::logic_error("input from streams not yet implemented"));
+}
+
diff --git a/ginac/operators.h b/ginac/operators.h
new file mode 100644 (file)
index 0000000..dfd985f
--- /dev/null
@@ -0,0 +1,110 @@
+/** @file operators.h
+ *
+ *  Interface to GiNaC's overloaded operators. */
+
+#ifndef _OPERATORS_H_
+#define _OPERATORS_H_
+
+#include <iostream>
+#include "basic.h"
+#include "ex.h"
+#include "numeric.h"
+#include "relational.h"
+
+
+// binary arithmetic operators ex with ex
+ex operator+(ex const & lh, ex const & rh);
+ex operator-(ex const & lh, ex const & rh);
+ex operator*(ex const & lh, ex const & rh);
+ex operator/(ex const & lh, ex const & rh);
+ex operator%(ex const & lh, ex const & rh); // non-commutative multiplication
+
+/*
+
+// binary arithmetic operators ex with numeric
+ex operator+(ex const & lh, numeric const & rh);
+ex operator-(ex const & lh, numeric const & rh);
+ex operator*(ex const & lh, numeric const & rh);
+ex operator/(ex const & lh, numeric const & rh);
+ex operator%(ex const & lh, numeric const & rh); // non-commutative multiplication
+
+// binary arithmetic operators numeric with ex
+ex operator+(numeric const & lh, ex const & rh);
+ex operator-(numeric const & lh, ex const & rh);
+ex operator*(numeric const & lh, ex const & rh);
+ex operator/(numeric const & lh, ex const & rh);
+ex operator%(numeric const & lh, ex const & rh); // non-commutative multiplication
+
+*/
+
+// binary arithmetic operators numeric with numeric
+numeric operator+(numeric const & lh, numeric const & rh);
+numeric operator-(numeric const & lh, numeric const & rh);
+numeric operator*(numeric const & lh, numeric const & rh);
+numeric operator/(numeric const & lh, numeric const & rh);
+
+// binary arithmetic assignment operators with ex
+ex const & operator+=(ex & lh, ex const & rh);
+ex const & operator-=(ex & lh, ex const & rh);
+ex const & operator*=(ex & lh, ex const & rh);
+ex const & operator/=(ex & lh, ex const & rh);
+ex const & operator%=(ex & lh, ex const & rh); // non-commutative multiplication
+
+/*
+  
+// binary arithmetic assignment operators with numeric
+ex const & operator+=(ex & lh, numeric const & rh);
+ex const & operator-=(ex & lh, numeric const & rh);
+ex const & operator*=(ex & lh, numeric const & rh);
+ex const & operator/=(ex & lh, numeric const & rh);
+ex const & operator%=(ex & lh, numeric const & rh); // non-commutative multiplication
+
+*/
+
+// binary arithmetic assignment operators with numeric
+numeric const & operator+=(numeric & lh, numeric const & rh);
+numeric const & operator-=(numeric & lh, numeric const & rh);
+numeric const & operator*=(numeric & lh, numeric const & rh);
+numeric const & operator/=(numeric & lh, numeric const & rh);
+
+// unary operators
+ex operator+(ex const & lh);
+ex operator-(ex const & lh);
+
+numeric operator+(numeric const & lh);
+numeric operator-(numeric const & lh);
+
+// binary relational operators ex with ex
+relational operator==(ex const & lh, ex const & rh);
+relational operator!=(ex const & lh, ex const & rh);
+relational operator<(ex const & lh, ex const & rh);
+relational operator<=(ex const & lh, ex const & rh);
+relational operator>(ex const & lh, ex const & rh);
+relational operator>=(ex const & lh, ex const & rh);
+
+/*
+
+// binary relational operators ex with numeric
+relational operator==(ex const & lh, numeric const & rh);
+relational operator!=(ex const & lh, numeric const & rh);
+relational operator<(ex const & lh, numeric const & rh);
+relational operator<=(ex const & lh, numeric const & rh);
+relational operator>(ex const & lh, numeric const & rh);
+relational operator>=(ex const & lh, numeric const & rh);
+
+// binary relational operators numeric with ex
+relational operator==(numeric const & lh, ex const & rh);
+relational operator!=(numeric const & lh, ex const & rh);
+relational operator<(numeric const & lh, ex const & rh);
+relational operator<=(numeric const & lh, ex const & rh);
+relational operator>(numeric const & lh, ex const & rh);
+relational operator>=(numeric const & lh, ex const & rh);
+
+*/
+
+// input/output stream operators
+ostream & operator<<(ostream & os, ex const & e);
+istream & operator>>(istream & is, ex & e);
+
+#endif // ndef _OPERATORS_H_
+
diff --git a/ginac/power.cpp b/ginac/power.cpp
new file mode 100644 (file)
index 0000000..f0b5c5a
--- /dev/null
@@ -0,0 +1,695 @@
+/** @file power.cpp
+ *
+ *  Implementation of GiNaC's symbolic exponentiation (basis^exponent). */
+
+#include <vector>
+#include <iostream>
+#include <stdexcept>
+
+#include "ginac.h"
+
+typedef vector<int> intvector;
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+power::power() : basic(TINFO_POWER)
+{
+    debugmsg("power default constructor",LOGLEVEL_CONSTRUCT);
+}
+
+power::~power()
+{
+    debugmsg("power destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+power::power(power const & other)
+{
+    debugmsg("power copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+power const & power::operator=(power const & other)
+{
+    debugmsg("power operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void power::copy(power const & other)
+{
+    basic::copy(other);
+    basis=other.basis;
+    exponent=other.exponent;
+}
+
+void power::destroy(bool call_parent)
+{
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+power::power(ex const & lh, ex const & rh) : basic(TINFO_POWER), basis(lh), exponent(rh)
+{
+    debugmsg("power constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+    ASSERT(basis.return_type()==return_types::commutative);
+}
+
+power::power(ex const & lh, numeric const & rh) : basic(TINFO_POWER), basis(lh), exponent(rh)
+{
+    debugmsg("power constructor from ex,numeric",LOGLEVEL_CONSTRUCT);
+    ASSERT(basis.return_type()==return_types::commutative);
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * power::duplicate() const
+{
+    debugmsg("power duplicate",LOGLEVEL_DUPLICATE);
+    return new power(*this);
+}
+
+bool power::info(unsigned inf) const
+{
+    if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial) {
+        return exponent.info(info_flags::nonnegint);
+    } else if (inf==info_flags::rational_function) {
+        return exponent.info(info_flags::integer);
+    } else {
+        return basic::info(inf);
+    }
+}
+
+int power::nops() const
+{
+    return 2;
+}
+
+ex & power::let_op(int const i)
+{
+    ASSERT(i>=0);
+    ASSERT(i<2);
+
+    return i==0 ? basis : exponent;
+}
+
+int power::degree(symbol const & s) const
+{
+    if (is_exactly_of_type(*exponent.bp,numeric)) {
+       if ((*basis.bp).compare(s)==0)
+            return ex_to_numeric(exponent).to_int();
+        else
+            return basis.degree(s) * ex_to_numeric(exponent).to_int();
+    }
+    return 0;
+}
+
+int power::ldegree(symbol const & s) const 
+{
+    if (is_exactly_of_type(*exponent.bp,numeric)) {
+       if ((*basis.bp).compare(s)==0)
+            return ex_to_numeric(exponent).to_int();
+        else
+            return basis.ldegree(s) * ex_to_numeric(exponent).to_int();
+    }
+    return 0;
+}
+
+ex power::coeff(symbol const & s, int const n) const
+{
+    if ((*basis.bp).compare(s)!=0) {
+        // basis not equal to s
+        if (n==0) {
+            return *this;
+        } else {
+            return exZERO();
+        }
+    } else if (is_exactly_of_type(*exponent.bp,numeric)&&
+               (static_cast<numeric const &>(*exponent.bp).compare(numeric(n))==0)) {
+        return exONE();
+    }
+
+    return exZERO();
+}
+
+ex power::eval(int level) const
+{
+    // simplifications: ^(x,0) -> 1 (0^0 handled here)
+    //                  ^(x,1) -> x
+    //                  ^(0,x) -> 0 (except if x is real and negative, in which case an exception is thrown)
+    //                  ^(1,x) -> 1
+    //                  ^(c1,c2) -> *(c1^n,c1^(c2-n)) (c1, c2 numeric(), 0<(c2-n)<1 except if c1,c2 are rational, but c1^c2 is not)
+    //                  ^(^(x,c1),c2) -> ^(x,c1*c2) (c1, c2 numeric(), c2 integer or -1 < c1 <= 1, case c1=1 should not happen, see below!)
+    //                  ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
+    //                  ^(*(x,c1),c2) -> ^(x,c2)*c1^c2 (c1, c2 numeric(), c1>0)
+    //                  ^(*(x,c1),c2) -> ^(-x,c2)*c1^c2 (c1, c2 numeric(), c1<0)
+    
+    debugmsg("power eval",LOGLEVEL_MEMBER_FUNCTION);
+
+    if ((level==1)&&(flags & status_flags::evaluated)) {
+        return *this;
+    } else if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    
+    ex const & ebasis    = level==1 ? basis    : basis.eval(level-1);
+    ex const & eexponent = level==1 ? exponent : exponent.eval(level-1);
+
+    bool basis_is_numerical=0;
+    bool exponent_is_numerical=0;
+    numeric * num_basis;
+    numeric * num_exponent;
+
+    if (is_exactly_of_type(*ebasis.bp,numeric)) {
+        basis_is_numerical=1;
+        num_basis=static_cast<numeric *>(ebasis.bp);
+    }
+    if (is_exactly_of_type(*eexponent.bp,numeric)) {
+        exponent_is_numerical=1;
+        num_exponent=static_cast<numeric *>(eexponent.bp);
+    }
+
+    // ^(x,0) -> 1 (0^0 also handled here)
+    if (eexponent.is_zero())
+        return exONE();
+
+    // ^(x,1) -> x
+    if (eexponent.is_equal(exONE()))
+        return ebasis;
+
+    // ^(0,x) -> 0 (except if x is real and negative)
+    if (ebasis.is_zero()) {
+        if (exponent_is_numerical && num_exponent->is_negative()) {
+            throw(std::overflow_error("power::eval(): division by zero"));
+        } else
+            return exZERO();
+    }
+
+    // ^(1,x) -> 1
+    if (ebasis.is_equal(exONE()))
+        return exONE();
+
+    if (basis_is_numerical && exponent_is_numerical) {
+        // ^(c1,c2) -> c1^c2 (c1, c2 numeric(),
+        // except if c1,c2 are rational, but c1^c2 is not)
+        bool basis_is_rational = num_basis->is_rational();
+        bool exponent_is_rational = num_exponent->is_rational();
+        numeric res = (*num_basis).power(*num_exponent);
+        
+        if ((!basis_is_rational || !exponent_is_rational)
+            || res.is_rational()) {
+            return res;
+        }
+        ASSERT(!num_exponent->is_integer());  // has been handled by now
+        // ^(c1,n/m) -> *(c1^q,c1^(n/m-q)), 0<(n/m-h)<1, q integer
+        if (basis_is_rational && exponent_is_rational
+            && num_exponent->is_real()
+            && !num_exponent->is_integer()) {
+            numeric r, q, n, m;
+            n = num_exponent->numer();
+            m = num_exponent->denom();
+            q = iquo(n, m, r);
+            if (r.is_negative()) {
+                r = r.add(m);
+                q = q.sub(numONE());
+            }
+            if (q.is_zero())  // the exponent was in the allowed range 0<(n/m)<1
+                return this->hold();
+            else {
+                epvector res(2);
+                res.push_back(expair(ebasis,r.div(m)));
+                res.push_back(expair(ex(num_basis->power(q)),exONE()));
+                return (new mul(res))->setflag(status_flags::dynallocated | status_flags::evaluated);
+                /*return mul(num_basis->power(q),
+                           power(ex(*num_basis),ex(r.div(m)))).hold();
+                */
+                /* return (new mul(num_basis->power(q),
+                   power(*num_basis,r.div(m)).hold()))->setflag(status_flags::dynallocated | status_flags::evaluated);
+                */
+            }
+        }
+    }
+
+    // ^(^(x,c1),c2) -> ^(x,c1*c2)
+    // (c1, c2 numeric(), c2 integer or -1 < c1 <= 1,
+    // case c1=1 should not happen, see below!)
+    if (exponent_is_numerical && is_ex_exactly_of_type(ebasis,power)) {
+        power const & sub_power=ex_to_power(ebasis);
+        ex const & sub_basis=sub_power.basis;
+        ex const & sub_exponent=sub_power.exponent;
+        if (is_ex_exactly_of_type(sub_exponent,numeric)) {
+            numeric const & num_sub_exponent=ex_to_numeric(sub_exponent);
+            ASSERT(num_sub_exponent!=numeric(1));
+            if (num_exponent->is_integer() || abs(num_sub_exponent)<1) {
+                return power(sub_basis,num_sub_exponent.mul(*num_exponent));
+            }
+        }
+    }
+    
+    // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
+    if (exponent_is_numerical && num_exponent->is_integer() &&
+        is_ex_exactly_of_type(ebasis,mul)) {
+        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 (exponent_is_numerical && is_ex_exactly_of_type(ebasis,mul)) {
+        ASSERT(!num_exponent->is_integer()); // should have been handled above
+        mul const & mulref=ex_to_mul(ebasis);
+        if (!mulref.overall_coeff.is_equal(exONE())) {
+            numeric const & num_coeff=ex_to_numeric(mulref.overall_coeff);
+            if (num_coeff.is_real()) {
+                if (num_coeff.is_positive()>0) {
+                    mul * mulp=new mul(mulref);
+                    mulp->overall_coeff=exONE();
+                    mulp->clearflag(status_flags::evaluated);
+                    mulp->clearflag(status_flags::hash_calculated);
+                    return (new mul(power(*mulp,exponent),
+                                    power(num_coeff,*num_exponent)))->
+                        setflag(status_flags::dynallocated);
+                } else {
+                    ASSERT(num_coeff.compare(numZERO())<0);
+                    if (num_coeff.compare(numMINUSONE())!=0) {
+                        mul * mulp=new mul(mulref);
+                        mulp->overall_coeff=exMINUSONE();
+                        mulp->clearflag(status_flags::evaluated);
+                        mulp->clearflag(status_flags::hash_calculated);
+                        return (new mul(power(*mulp,exponent),
+                                        power(abs(num_coeff),*num_exponent)))->
+                            setflag(status_flags::dynallocated);
+                    }
+                }
+            }
+        }
+    }
+        
+    if (are_ex_trivially_equal(ebasis,basis) &&
+        are_ex_trivially_equal(eexponent,exponent)) {
+        return this->hold();
+    }
+    return (new power(ebasis, eexponent))->setflag(status_flags::dynallocated |
+                                                   status_flags::evaluated);
+}
+
+ex power::evalf(int level) const
+{
+    debugmsg("power evalf",LOGLEVEL_MEMBER_FUNCTION);
+
+    ex ebasis;
+    ex eexponent;
+    
+    if (level==1) {
+        ebasis=basis;
+        eexponent=exponent;
+    } else if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    } else {
+        ebasis=basis.evalf(level-1);
+        eexponent=exponent.evalf(level-1);
+    }
+
+    return power(ebasis,eexponent);
+}
+
+ex power::subs(lst const & ls, lst const & lr) const
+{
+    ex const & subsed_basis=basis.subs(ls,lr);
+    ex const & subsed_exponent=exponent.subs(ls,lr);
+
+    if (are_ex_trivially_equal(basis,subsed_basis)&&
+        are_ex_trivially_equal(exponent,subsed_exponent)) {
+        return *this;
+    }
+    
+    return power(subsed_basis, subsed_exponent);
+}
+
+ex power::simplify_ncmul(exvector const & v) const
+{
+    return basic::simplify_ncmul(v);
+}
+
+// protected
+
+int power::compare_same_type(basic const & other) const
+{
+    ASSERT(is_exactly_of_type(other, power));
+    power const & o=static_cast<power const &>(const_cast<basic &>(other));
+
+    int cmpval;
+    cmpval=basis.compare(o.basis);
+    if (cmpval==0) {
+        return exponent.compare(o.exponent);
+    }
+    return cmpval;
+}
+
+unsigned power::return_type(void) const
+{
+    return basis.return_type();
+}
+   
+unsigned power::return_type_tinfo(void) const
+{
+    return basis.return_type_tinfo();
+}
+
+ex power::expand(unsigned options) const
+{
+    ex expanded_basis=basis.expand(options);
+
+    if (!is_ex_exactly_of_type(exponent,numeric)||
+        !ex_to_numeric(exponent).is_integer()) {
+        if (are_ex_trivially_equal(basis,expanded_basis)) {
+            return this->hold();
+        } else {
+            return (new power(expanded_basis,exponent))->
+                    setflag(status_flags::dynallocated);
+        }
+    }
+
+    // integer numeric exponent
+    numeric const & num_exponent=ex_to_numeric(exponent);
+    int int_exponent = num_exponent.to_int();
+
+    if (int_exponent > 0 && is_ex_exactly_of_type(expanded_basis,add)) {
+        return expand_add(ex_to_add(expanded_basis), int_exponent);
+    }
+
+    if (is_ex_exactly_of_type(expanded_basis,mul)) {
+        return expand_mul(ex_to_mul(expanded_basis), num_exponent);
+    }
+
+    // cannot expand further
+    if (are_ex_trivially_equal(basis,expanded_basis)) {
+        return this->hold();
+    } else {
+        return (new power(expanded_basis,exponent))->
+               setflag(status_flags::dynallocated);
+    }
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+ex power::expand_add(add const & a, int const n) const
+{
+    // expand a^n where a is an add and n is an integer
+
+    if (n==2) {
+        return expand_add_2(a);
+    }
+    
+    int m=a.nops();
+    exvector sum;
+    sum.reserve((n+1)*(m-1));
+    intvector k(m-1);
+    intvector k_cum(m-1); // k_cum[l]:=sum(i=0,l,k[l]);
+    intvector upper_limit(m-1);
+    int l;
+    
+    for (int l=0; l<m-1; l++) {
+        k[l]=0;
+        k_cum[l]=0;
+        upper_limit[l]=n;
+    }
+
+    while (1) {
+        exvector term;
+        term.reserve(m+1);
+        for (l=0; l<m-1; l++) {
+            ex const & b=a.op(l);
+            ASSERT(!is_ex_exactly_of_type(b,add));
+            ASSERT(!is_ex_exactly_of_type(b,power)||
+                   !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
+                   !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer());
+            if (is_ex_exactly_of_type(b,mul)) {
+                term.push_back(expand_mul(ex_to_mul(b),numeric(k[l])));
+            } else {
+                term.push_back(power(b,k[l]));
+            }
+        }
+
+        ex const & b=a.op(l);
+        ASSERT(!is_ex_exactly_of_type(b,add));
+        ASSERT(!is_ex_exactly_of_type(b,power)||
+               !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
+               !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer());
+        if (is_ex_exactly_of_type(b,mul)) {
+            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]));
+        }
+
+        numeric f=binomial(numeric(n),numeric(k[0]));
+        for (l=1; l<m-1; l++) {
+            f=f*binomial(numeric(n-k_cum[l-1]),numeric(k[l]));
+        }
+        term.push_back(f);
+
+        /*
+        cout << "begin term" << endl;
+        for (int i=0; i<m-1; i++) {
+            cout << "k[" << i << "]=" << k[i] << endl;
+            cout << "k_cum[" << i << "]=" << k_cum[i] << endl;
+            cout << "upper_limit[" << i << "]=" << upper_limit[i] << endl;
+        }
+        for (exvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
+            cout << *cit << endl;
+        }
+        cout << "end term" << endl;
+        */
+
+        // TODO: optimize!!!!!!!!
+        sum.push_back((new mul(term))->setflag(status_flags::dynallocated));
+        
+        // increment k[]
+        l=m-2;
+        while ((l>=0)&&((++k[l])>upper_limit[l])) {
+            k[l]=0;    
+            l--;
+        }
+        if (l<0) break;
+
+        // recalc k_cum[] and upper_limit[]
+        if (l==0) {
+            k_cum[0]=k[0];
+        } else {
+            k_cum[l]=k_cum[l-1]+k[l];
+        }
+        for (int 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++) {
+            upper_limit[i]=n-k_cum[i-1];
+        }   
+    }
+    return (new add(sum))->setflag(status_flags::dynallocated);
+}
+
+/*
+ex power::expand_add_2(add const & a) const
+{
+    // special case: expand a^2 where a is an add
+
+    epvector sum;
+    sum.reserve((a.seq.size()*(a.seq.size()+1))/2);
+    epvector::const_iterator last=a.seq.end();
+
+    for (epvector::const_iterator cit0=a.seq.begin(); cit0!=last; ++cit0) {
+        ex const & b=a.recombine_pair_to_ex(*cit0);
+        ASSERT(!is_ex_exactly_of_type(b,add));
+        ASSERT(!is_ex_exactly_of_type(b,power)||
+               !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
+               !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer());
+        if (is_ex_exactly_of_type(b,mul)) {
+            sum.push_back(a.split_ex_to_pair(expand_mul(ex_to_mul(b),numTWO())));
+        } else {
+            sum.push_back(a.split_ex_to_pair((new power(b,exTWO()))->
+                                              setflag(status_flags::dynallocated)));
+        }
+        for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) {
+            sum.push_back(a.split_ex_to_pair((new mul(a.recombine_pair_to_ex(*cit0),
+                                                      a.recombine_pair_to_ex(*cit1)))->
+                                              setflag(status_flags::dynallocated),
+                                             exTWO()));
+        }
+    }
+
+    ASSERT(sum.size()==(a.seq.size()*(a.seq.size()+1))/2);
+
+    return (new add(sum))->setflag(status_flags::dynallocated);
+}
+*/
+
+ex power::expand_add_2(add const & a) const
+{
+    // special case: expand a^2 where a is an add
+
+    epvector sum;
+    unsigned a_nops=a.nops();
+    sum.reserve((a_nops*(a_nops+1))/2);
+    epvector::const_iterator last=a.seq.end();
+
+    // power(+(x,...,z;c),2)=power(+(x,...,z;0),2)+2*c*+(x,...,z;0)+c*c
+    // first part: ignore overall_coeff and expand other terms
+    for (epvector::const_iterator cit0=a.seq.begin(); cit0!=last; ++cit0) {
+        ex const & r=(*cit0).rest;
+        ex const & c=(*cit0).coeff;
+        
+        ASSERT(!is_ex_exactly_of_type(r,add));
+        ASSERT(!is_ex_exactly_of_type(r,power)||
+               !is_ex_exactly_of_type(ex_to_power(r).exponent,numeric)||
+               !ex_to_numeric(ex_to_power(r).exponent).is_pos_integer()||
+               !is_ex_exactly_of_type(ex_to_power(r).basis,add)||
+               !is_ex_exactly_of_type(ex_to_power(r).basis,mul)||
+               !is_ex_exactly_of_type(ex_to_power(r).basis,power));
+
+        if (are_ex_trivially_equal(c,exONE())) {
+            if (is_ex_exactly_of_type(r,mul)) {
+                sum.push_back(expair(expand_mul(ex_to_mul(r),numTWO()),exONE()));
+            } else {
+                sum.push_back(expair((new power(r,exTWO()))->setflag(status_flags::dynallocated),
+                                     exONE()));
+            }
+        } else {
+            if (is_ex_exactly_of_type(r,mul)) {
+                sum.push_back(expair(expand_mul(ex_to_mul(r),numTWO()),
+                                     ex_to_numeric(c).power_dyn(numTWO())));
+            } else {
+                sum.push_back(expair((new power(r,exTWO()))->setflag(status_flags::dynallocated),
+                                     ex_to_numeric(c).power_dyn(numTWO())));
+            }
+        }
+            
+        for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) {
+            ex const & r1=(*cit1).rest;
+            ex const & c1=(*cit1).coeff;
+            sum.push_back(a.combine_ex_with_coeff_to_pair((new mul(r,r1))->setflag(status_flags::dynallocated),
+                                                          numTWO().mul(ex_to_numeric(c)).mul_dyn(ex_to_numeric(c1))));
+        }
+    }
+
+    ASSERT(sum.size()==(a.seq.size()*(a.seq.size()+1))/2);
+
+    // second part: add terms coming from overall_factor (if != 0)
+    if (!a.overall_coeff.is_equal(exZERO())) {
+        for (epvector::const_iterator cit=a.seq.begin(); cit!=a.seq.end(); ++cit) {
+            sum.push_back(a.combine_pair_with_coeff_to_pair(*cit,ex_to_numeric(a.overall_coeff).mul_dyn(numTWO())));
+        }
+        sum.push_back(expair(ex_to_numeric(a.overall_coeff).power_dyn(numTWO()),exONE()));
+    }
+        
+    ASSERT(sum.size()==(a_nops*(a_nops+1))/2);
+    
+    return (new add(sum))->setflag(status_flags::dynallocated);
+}
+
+ex power::expand_mul(mul const & m, numeric const & n) const
+{
+    // expand m^n where m is a mul and n is and integer
+
+    if (n.is_equal(numZERO())) {
+        return exONE();
+    }
+    
+    epvector distrseq;
+    distrseq.reserve(m.seq.size());
+    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)) {
+            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()
+            // since n is an integer
+            distrseq.push_back(expair((*cit).rest,
+                                      ex_to_numeric((*cit).coeff).mul(n)));
+        }
+        ++cit;
+    }
+    return (new mul(distrseq,ex_to_numeric(m.overall_coeff).power_dyn(n)))
+                 ->setflag(status_flags::dynallocated);
+}
+
+/*
+ex power::expand_commutative_3(ex const & basis, numeric const & exponent,
+                             unsigned options) const
+{
+    // obsolete
+
+    exvector distrseq;
+    epvector splitseq;
+
+    add const & addref=static_cast<add const &>(*basis.bp);
+
+    splitseq=addref.seq;
+    splitseq.pop_back();
+    ex first_operands=add(splitseq);
+    ex last_operand=addref.recombine_pair_to_ex(*(addref.seq.end()-1));
+    
+    int n=exponent.to_int();
+    for (int k=0; k<=n; k++) {
+        distrseq.push_back(binomial(n,k)*power(first_operands,numeric(k))*
+                           power(last_operand,numeric(n-k)));
+    }
+    return ex((new add(distrseq))->setflag(status_flags::sub_expanded |
+                                           status_flags::expanded |
+                                           status_flags::dynallocated  )).
+           expand(options);
+}
+*/
+
+/*
+ex power::expand_noncommutative(ex const & basis, numeric const & exponent,
+                                unsigned options) const
+{
+    ex rest_power=ex(power(basis,exponent.add(numMINUSONE()))).
+                  expand(options | expand_options::internal_do_not_expand_power_operands);
+
+    return ex(mul(rest_power,basis),0).
+           expand(options | expand_options::internal_do_not_expand_mul_operands);
+}
+*/
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned power::precedence=60;
+
+//////////
+// global constants
+//////////
+
+const power some_power;
+type_info const & typeid_power=typeid(some_power);
diff --git a/ginac/power.h b/ginac/power.h
new file mode 100644 (file)
index 0000000..ed9c146
--- /dev/null
@@ -0,0 +1,103 @@
+/** @file power.h
+ *
+ *  Interface to GiNaC's symbolic exponentiation (basis^exponent). */
+
+#ifndef _POWER_H_
+#define _POWER_H_
+
+class power;
+class numeric;
+class add;
+
+/** This class holds a two-component object, a basis and and exponent
+ *  representing exponentiation. */
+class power : public basic
+{
+    friend class mul;
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    power();
+    ~power();
+    power(power const & other);
+    power const & operator=(power const & other);
+protected:
+    void copy(power const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    power(ex const & lh, ex const & rh);
+    power(ex const & lh, numeric const & rh);
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+    int nops() const;
+    ex & let_op(int const i);
+    int degree(symbol const & s) const;
+    int ldegree(symbol const & s) const;
+    ex coeff(symbol const & s, int const n=1) const;
+    ex eval(int level=0) const;
+    ex evalf(int level=0) const;
+    ex diff(symbol const & s) const;
+    ex series(symbol const & s, ex const & point, int order) const;
+    ex subs(lst const & ls, lst const & lr) const;
+    ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+    ex simplify_ncmul(exvector const & v) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    ex expand(unsigned options=0) const;
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+protected:
+    ex expand_add(add const & a, int const n) const;
+    ex expand_add_2(add const & a) const;
+    ex expand_mul(mul const & m, numeric const & n) const;
+    //ex expand_commutative_3(ex const & basis, numeric const & exponent,
+    //                         unsigned options) const;
+    // ex expand_noncommutative(ex const & basis, numeric const & exponent, unsigned options) const;
+
+// member variables
+
+protected:
+    ex basis;
+    ex exponent;
+    static unsigned precedence;
+};
+
+// global constants
+
+extern const power some_power;
+extern type_info const & typeid_power;
+
+#define ex_to_power(X) static_cast<power const &>(*(X).bp)
+
+// wrapper functions
+
+/** Symbolic exponentiation.  Returns a power-object as a new expression.
+ *
+ *  @param b the basis expression
+ *  @param e the exponent expression */
+inline ex pow(ex const & b, ex const & e)
+{ return power(b,e); }
+
+/** Square root expression.  Returns a power-object with exponent 1/2 as a new
+ *  expression.  */
+inline ex sqrt(ex const & a)
+{ return power(a,exHALF()); }
+
+#endif // ndef _POWER_H_
+
diff --git a/ginac/print.cpp b/ginac/print.cpp
new file mode 100644 (file)
index 0000000..6cfd0a1
--- /dev/null
@@ -0,0 +1,287 @@
+/** @file print.cpp
+ *
+ *  The methods .print() are responsible for the nice default-output of
+ *  objects.  All related helper-functions go in here as well. */
+
+#include <iostream>
+
+#include "ginac.h"
+
+void ex::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("ex print",LOGLEVEL_PRINT);
+    ASSERT(bp!=0);
+    bp->print(os,upper_precedence);
+}
+
+void ex::dbgprint(void) const
+{
+    debugmsg("ex dbgprint",LOGLEVEL_PRINT);
+    ASSERT(bp!=0);
+    bp->dbgprint();
+}
+
+void basic::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("basic print",LOGLEVEL_PRINT);
+    os << "[basic object]";
+}
+
+void basic::dbgprint(void) const
+{
+    print(cerr);
+    cerr << endl;
+}
+
+void symbol::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("symbol print",LOGLEVEL_PRINT);
+    os << name;
+}
+
+void constant::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("constant print",LOGLEVEL_PRINT);
+    os << name;
+}
+
+void power::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("power print",LOGLEVEL_PRINT);
+#if 1
+    if (precedence<=upper_precedence) os << "(";
+    basis.print(os,precedence);
+    os << "^";
+    exponent.print(os,precedence);
+    if (precedence<=upper_precedence) os << ")";
+#else
+    os << "pow(" << basis << "," << exponent << ")";
+#endif
+}
+
+void fail::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("fail print",LOGLEVEL_PRINT);
+    os << "FAIL";
+}
+
+void expairseq::printpair(ostream & os, expair const & p, unsigned upper_precedence) const
+{
+    os << "[[";
+    p.rest.bp->print(os,precedence);
+    os << ",";
+    p.coeff.bp->print(os,precedence);
+    os << "]]";
+}
+
+/*
+void expairseq::printseq(ostream & os, char delim, unsigned this_precedence,
+                         unsigned upper_precedence) const
+{
+    if (this_precedence<=upper_precedence) os << "(";
+    epvector::const_iterator itt,it,it_last,it_start;
+    it_last=seq.end();
+    --it_last;
+    it_start=seq.begin();
+
+    switch (delim) {
+    case '+':
+        for (it=seq.begin(); it!=it_last; ++it) {
+            itt = it +1;
+            expair const & k = *itt;
+            printpair(os,*it, this_precedence);
+            if (((is_ex_of_type(k.rest, numeric)) && (k.coeff*k.rest > 0) ) || ((!is_ex_of_type(k.rest, numeric)) && (k.coeff >0))){
+                os << "+";
+            }
+        }
+        printpair(os,*it,this_precedence);
+        break;
+        
+    case '*':
+        for (it = it_last ; it!=it_start; --it) {
+            if ((*it).rest.is_equal(exMINUSONE()) &&
+                (*it).coeff.is_equal(exONE())) {
+                os << "-";
+            } else {
+                printpair(os, *it,this_precedence);
+                os << delim;
+            }
+        }
+        printpair(os,*it,this_precedence);
+        break;
+    default:
+        clog << "Nobody expects the Spanish Inquisition: "
+             << "deliminator unknown!" << endl;
+    }
+    if (this_precedence<=upper_precedence) os << ")";
+}
+*/
+
+void expairseq::printseq(ostream & os, char delim, unsigned this_precedence,
+                         unsigned upper_precedence) const
+{
+    if (this_precedence<=upper_precedence) os << "(";
+    epvector::const_iterator it,it_last;
+    it_last=seq.end();
+    --it_last;
+    for (it=seq.begin(); it!=it_last; ++it) {
+        printpair(os,*it,this_precedence);
+        os << delim;
+    }
+    printpair(os,*it,this_precedence);
+    if (!overall_coeff.is_equal(default_overall_coeff())) {
+        os << delim << overall_coeff;
+    }
+    if (this_precedence<=upper_precedence) os << ")";
+}
+    
+void expairseq::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("expairseq print",LOGLEVEL_PRINT);
+    os << "[[";
+    printseq(os,',',precedence,upper_precedence);
+    os << "]]";
+}
+
+void add::printpair(ostream & os, expair const & p, unsigned upper_precedence) const
+{
+    os << "(";
+    if (p.coeff == -1) {
+        os << "-";
+    } else {
+        if (p.coeff != 1) {
+            os << p.coeff;
+            os << "*";
+        }
+    }
+    os << p.rest;
+    os << ")";
+}
+    
+void add::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("add print",LOGLEVEL_PRINT);
+    if (precedence<=upper_precedence) os << "(";
+    bool first=true;
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        if (!first) {
+            if (cit->coeff > 0) os << '+';
+        } else {
+            first=false;
+        }
+        if (cit->coeff == -1) {
+            os << "-";
+        } else {
+            if (cit->coeff != 1) {
+                os << cit->coeff;
+                os << "*";
+            }
+        }
+        os << cit->rest;
+    }
+    if (!overall_coeff.is_equal(exZERO())) {
+        if (overall_coeff > 0) os << '+';
+        os << overall_coeff;
+    }
+    if (precedence<=upper_precedence) os << ")";
+}
+
+void mul::printpair(ostream & os, expair const & p, unsigned upper_precedence) const
+{
+    os << "(";
+    if (p.coeff.compare(exONE())==0) {
+        p.rest.print(os,upper_precedence);
+    } else {
+        // outer parens around ex needed for broken gcc-2.95 parser:
+        (ex(power(p.rest,p.coeff))).print(os,upper_precedence);
+    }
+    os << ")";
+}
+    
+void mul::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("mul print",LOGLEVEL_PRINT);
+    if (precedence<=upper_precedence) os << "(";
+    bool first=true;
+    if (!overall_coeff.is_equal(exONE())) {
+        overall_coeff.print(os,precedence);
+        first=false;
+    }
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        if (!first) {
+            os << '*';
+        } else {
+            first=false;
+        }
+        recombine_pair_to_ex(*cit).print(os,precedence);
+    }
+    if (precedence<=upper_precedence) os << ")";
+}
+
+void ncmul::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("ncmul print",LOGLEVEL_PRINT);
+    printseq(os,'(','%',')',precedence,upper_precedence);
+}
+
+/*void function::print(ostream & os, unsigned upper_precedence) const
+ *{
+ *    debugmsg("function print",LOGLEVEL_PRINT);
+ *    os << name;
+ *    printseq(os,'(',',',')',exprseq::precedence,function::precedence);
+ *}*/
+
+void series::print(ostream &os, unsigned upper_precedence) const
+{
+       debugmsg("symbol print", LOGLEVEL_PRINT);
+       convert_to_poly().print(os, upper_precedence);
+}
+
+void relational::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("relational print",LOGLEVEL_PRINT);
+    if (precedence<=upper_precedence) os << "(";
+    lh.print(os,precedence);
+    switch (o) {
+    case equal:
+        os << "==";
+        break;
+    case not_equal:
+        os << "!=";
+        break;
+    case less:
+        os << "<";
+        break;
+    case less_or_equal:
+        os << "<=";
+        break;
+    case greater:
+        os << ">";
+        break;
+    case greater_or_equal:
+        os << ">=";
+        break;
+    default:
+        os << "(INVALID RELATIONAL OPERATOR)";
+    }
+    rh.print(os,precedence);
+    if (precedence<=upper_precedence) os << ")";
+}
+
+void matrix::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("matrix print",LOGLEVEL_PRINT);
+    os << "[[ ";
+    for (int r=0; r<row-1; ++r) {
+        os << "[[";
+        for (int c=0; c<col-1; ++c) {
+            os << m[r*col+c] << ",";
+        }
+        os << m[col*(r+1)-1] << "]], ";
+    }
+    os << "[[";
+    for (int c=0; c<col-1; ++c) {
+        os << m[(row-1)*col+c] << ",";
+    }
+    os << m[row*col-1] << "]] ]]";
+}
diff --git a/ginac/printcsrc.cpp b/ginac/printcsrc.cpp
new file mode 100644 (file)
index 0000000..418d384
--- /dev/null
@@ -0,0 +1,297 @@
+/** @file printcsrc.cpp
+ *
+ *  The methods .printcsrc() are responsible for C-source output of
+ *  objects.  All related helper-functions go in here as well. */
+
+#include <iostream>
+
+#include "ginac.h"
+
+/** Print expression as a C++ statement. The output looks like
+ *  "<type> <var_name> = <expression>;". The "type" parameter has an effect
+ *  on how number literals are printed.
+ *
+ *  @param os output stream
+ *  @param type variable type (one of the csrc_types)
+ *  @param var_name variable name to be printed */
+void ex::printcsrc(ostream & os, unsigned type, const char *var_name) const
+{
+    debugmsg("ex print csrc", LOGLEVEL_PRINT);
+    ASSERT(bp!=0);
+       switch (type) {
+               case csrc_types::ctype_float:
+                       os << "float ";
+                       break;
+               case csrc_types::ctype_double:
+                       os << "double ";
+                       break;
+               case csrc_types::ctype_cl_N:
+                       os << "cl_N ";
+                       break;
+       }
+    os << var_name << " = ";
+    bp->printcsrc(os, type, 0);
+    os << ";\n";
+}
+
+void basic::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("basic print csrc", LOGLEVEL_PRINT);
+}
+
+void numeric::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("numeric print csrc", LOGLEVEL_PRINT);
+       ios::fmtflags oldflags = os.flags();
+       os.setf(ios::scientific);
+    if (is_rational() && !is_integer()) {
+        if (compare(numZERO()) > 0) {
+            os << "(";
+                       if (type == csrc_types::ctype_cl_N)
+                               os << "cl_F(\"" << numer().evalf() << "\")";
+                       else
+                   os << numer().to_double();
+        } else {
+            os << "-(";
+                       if (type == csrc_types::ctype_cl_N)
+                               os << "cl_F(\"" << -numer().evalf() << "\")";
+                       else
+                   os << -numer().to_double();
+        }
+        os << "/";
+               if (type == csrc_types::ctype_cl_N)
+                       os << "cl_F(\"" << denom().evalf() << "\")";
+               else
+               os << denom().to_double();
+        os << ")";
+    } else {
+               if (type == csrc_types::ctype_cl_N)
+                       os << "cl_F(\"" << evalf() << "\")";
+               else
+               os << to_double();
+       }
+       os.flags(oldflags);
+}
+
+void symbol::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("symbol print csrc", LOGLEVEL_PRINT);
+    os << name;
+}
+
+void constant::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("constant print csrc",LOGLEVEL_PRINT);
+    os << name;
+}
+
+static void print_sym_pow(ostream & os, unsigned type, const symbol &x, int exp)
+{
+    // Optimal output of integer powers of symbols to aid compiler CSE
+    if (exp == 1) {
+        x.printcsrc(os, type, 0);
+    } else if (exp == 2) {
+        x.printcsrc(os, type, 0);
+        os << "*";
+        x.printcsrc(os, type, 0);
+    } else if (exp & 1) {
+        x.printcsrc(os, 0);
+        os << "*";
+        print_sym_pow(os, type, x, exp-1);
+    } else {
+        os << "(";
+        print_sym_pow(os, type, x, exp >> 1);
+        os << ")*(";
+        print_sym_pow(os, type, x, exp >> 1);
+        os << ")";
+    }
+}
+
+void power::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("power print csrc", LOGLEVEL_PRINT);
+
+       // Integer powers of symbols are printed in a special, optimized way
+    if (exponent.info(info_flags::integer) &&
+        (is_ex_exactly_of_type(basis, symbol) ||
+         is_ex_exactly_of_type(basis, constant))) {
+        int exp = ex_to_numeric(exponent).to_int();
+        if (exp > 0)
+            os << "(";
+        else {
+            exp = -exp;
+                       if (type == csrc_types::ctype_cl_N)
+                               os << "recip(";
+                       else
+                   os << "1.0/(";
+        }
+        print_sym_pow(os, type, static_cast<const symbol &>(*basis.bp), exp);
+        os << ")";
+
+       // <expr>^-1 is printed as "1.0/<expr>" or with the recip() function of CLN
+    } else if (exponent.compare(numMINUSONE()) == 0) {
+               if (type == csrc_types::ctype_cl_N)
+                       os << "recip(";
+               else
+               os << "1.0/(";
+        basis.bp->printcsrc(os, type, 0);
+               os << ")";
+
+       // Otherwise, use the pow() or expt() (CLN) functions
+    } else {
+               if (type == csrc_types::ctype_cl_N)
+                       os << "expt(";
+               else
+               os << "pow(";
+        basis.bp->printcsrc(os, type, 0);
+        os << ",";
+        exponent.bp->printcsrc(os, type, 0);
+        os << ")";
+    }
+}
+
+void add::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("add print csrc", LOGLEVEL_PRINT);
+    if (precedence <= upper_precedence)
+        os << "(";
+
+       // Print arguments, separated by "+"
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    while (it != itend) {
+
+               // If the coefficient is -1, it is replaced by a single minus sign
+        if (it->coeff.compare(numONE()) == 0) {
+               it->rest.bp->printcsrc(os, type, precedence);
+        } else if (it->coeff.compare(numMINUSONE()) == 0) {
+            os << "-";
+               it->rest.bp->printcsrc(os, type, precedence);
+               } else if (ex_to_numeric(it->coeff).numer().compare(numONE()) == 0) {
+               it->rest.bp->printcsrc(os, type, precedence);
+                       os << "/";
+            ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
+               } else if (ex_to_numeric(it->coeff).numer().compare(numMINUSONE()) == 0) {
+                       os << "-";
+               it->rest.bp->printcsrc(os, type, precedence);
+                       os << "/";
+            ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
+               } else {
+            it->coeff.bp->printcsrc(os, type, precedence);
+            os << "*";
+               it->rest.bp->printcsrc(os, type, precedence);
+        }
+
+               // Separator is "+", except it the following expression would have a leading minus sign
+        it++;
+        if (it != itend && !(it->coeff.compare(numZERO()) < 0 || (it->coeff.compare(numONE()) == 0 && is_ex_exactly_of_type(it->rest, numeric) && it->rest.compare(numZERO()) < 0)))
+            os << "+";
+    }
+    
+    if (!overall_coeff.is_equal(exZERO())) {
+        if (overall_coeff > 0) os << '+';
+        overall_coeff.bp->printcsrc(os,type,precedence);
+    }
+    
+    if (precedence <= upper_precedence)
+        os << ")";
+}
+
+void mul::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("mul print csrc", LOGLEVEL_PRINT);
+    if (precedence <= upper_precedence)
+        os << "(";
+
+    if (!overall_coeff.is_equal(exONE())) {
+        overall_coeff.bp->printcsrc(os,type,precedence);
+        os << "*";
+    }
+    
+       // Print arguments, separated by "*" or "/"
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    while (it != itend) {
+
+               // If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
+        if (it == seq.begin() && ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(numZERO()) < 0) {
+                       if (type == csrc_types::ctype_cl_N)
+                               os << "recip(";
+                       else
+                   os << "1.0/";
+               }
+
+               // If the exponent is 1 or -1, it is left out
+        if (it->coeff.compare(exONE()) == 0 || it->coeff.compare(numMINUSONE()) == 0)
+            it->rest.bp->printcsrc(os, type, precedence);
+        else
+            // outer parens around ex needed for broken gcc-2.95 parser:
+            (ex(power(it->rest, abs(ex_to_numeric(it->coeff))))).bp->printcsrc(os, type, upper_precedence);
+
+               // Separator is "/" for negative integer powers, "*" otherwise
+        it++;
+        if (it != itend) {
+            if (ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(numZERO()) < 0)
+                os << "/";
+            else
+                os << "*";
+        }
+    }
+    if (precedence <= upper_precedence)
+        os << ")";
+}
+
+void ncmul::printcsrc(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("ncmul print csrc",LOGLEVEL_PRINT);
+    exvector::const_iterator it;
+    exvector::const_iterator itend = seq.end()-1;
+    os << "ncmul(";
+    for (it=seq.begin(); it!=itend; ++it) {
+        (*it).bp->printcsrc(os,precedence);
+        os << ",";
+    }
+    (*it).bp->printcsrc(os,precedence);
+    os << ")";
+}
+
+void relational::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("relational print csrc", LOGLEVEL_PRINT);
+    if (precedence<=upper_precedence)
+               os << "(";
+
+       // Print left-hand expression
+    lh.bp->printcsrc(os, type, precedence);
+
+       // Print relational operator
+    switch (o) {
+           case equal:
+               os << "==";
+               break;
+           case not_equal:
+               os << "!=";
+               break;
+           case less:
+               os << "<";
+               break;
+           case less_or_equal:
+               os << "<=";
+               break;
+           case greater:
+               os << ">";
+               break;
+           case greater_or_equal:
+               os << ">=";
+               break;
+           default:
+               os << "(INVALID RELATIONAL OPERATOR)";
+                       break;
+    }
+
+       // Print right-hand operator
+    rh.bp->printcsrc(os, type, precedence);
+
+    if (precedence <= upper_precedence)
+               os << ")";
+}
diff --git a/ginac/printraw.cpp b/ginac/printraw.cpp
new file mode 100644 (file)
index 0000000..8315c81
--- /dev/null
@@ -0,0 +1,190 @@
+/** @file printraw.cpp
+ *
+ * print in ugly raw format, so brave developers can have a look at the
+ * underlying structure. */
+
+/* We are cheating here, because we don't want to include the underlying
+ * bignum package's headers again, so in this file we omit the definition of
+ * void numeric::printraw(ostream & os) const; */
+
+#include <iostream>
+
+#include "ginac.h"
+
+void ex::printraw(ostream & os) const
+{
+    debugmsg("ex printraw",LOGLEVEL_PRINT);
+    ASSERT(bp!=0);
+    os << "ex(";
+    bp->printraw(os);
+    os << ")";
+}
+
+void basic::printraw(ostream & os) const
+{
+    debugmsg("basic printraw",LOGLEVEL_PRINT);
+    os << "[basic object]";
+}
+
+void symbol::printraw(ostream & os) const
+{
+    debugmsg("symbol printraw",LOGLEVEL_PRINT);
+    os << "symbol(" << "name=" << name << ",serial=" << serial
+       << ",hash=" << hashvalue << ",flags=" << flags << ")";
+}
+
+void constant::printraw(ostream & os) const
+{
+    debugmsg("constant printraw",LOGLEVEL_PRINT);
+    os << "constant(" << name << ")";
+}
+
+void power::printraw(ostream & os) const
+{
+    debugmsg("power printraw",LOGLEVEL_PRINT);
+
+    os << "power(";
+    basis.printraw(os);
+    os << ",";
+    exponent.printraw(os);
+    os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+}
+
+void fail::printraw(ostream & os) const
+{
+    debugmsg("fail printraw",LOGLEVEL_PRINT);
+    os << "FAIL";
+}
+
+void expairseq::printraw(ostream & os) const
+{
+    debugmsg("expairseq printraw",LOGLEVEL_PRINT);
+
+    os << "expairseq(";
+    for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        os << "(";
+        (*cit).rest.printraw(os);
+        os << ",";
+        (*cit).coeff.printraw(os);
+        os << "),";
+    }
+    os << ")";
+}
+
+void add::printraw(ostream & os) const
+{
+    debugmsg("add printraw",LOGLEVEL_PRINT);
+
+    os << "+(";
+    for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        os << "(";
+        (*it).rest.bp->printraw(os);
+        os << ",";
+        (*it).coeff.bp->printraw(os);        
+        os << "),";
+    }
+    os << ",hash=" << hashvalue << ",flags=" << flags;
+    os << ")";
+}
+
+void mul::printraw(ostream & os) const
+{
+    debugmsg("mul printraw",LOGLEVEL_PRINT);
+
+    os << "*(";
+    for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        os << "(";
+        (*it).rest.bp->printraw(os);
+        os << ",";
+        (*it).coeff.bp->printraw(os);
+        os << "),";
+    }
+    os << ",hash=" << hashvalue << ",flags=" << flags;
+    os << ")";
+}
+
+void ncmul::printraw(ostream & os) const
+{
+    debugmsg("ncmul printraw",LOGLEVEL_PRINT);
+
+    os << "%(";
+    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+        (*it).bp->printraw(os);
+        os << ",";
+    }
+    os << ",hash=" << hashvalue << ",flags=" << flags;
+    os << ")";
+}
+
+/*void function::printraw(ostream & os) const
+ *{
+ *    debugmsg("function printraw",LOGLEVEL_PRINT);
+ *
+ *    os << "function." << name << "(";
+ *    for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
+ *        (*it).bp->print(os);
+ *        os << ",";
+ *    }
+ *    os << ")";
+ *}*/
+
+void series::printraw(ostream &os) const
+{
+       debugmsg("symbol printraw", LOGLEVEL_PRINT);
+       os << "series(" << var << ";" << point << ";";
+       for (epvector::const_iterator i=seq.begin(); i!=seq.end(); i++) {
+               os << "(" << (*i).rest << "," << (*i).coeff << "),";
+       }
+       os << ")";
+}
+
+void relational::printraw(ostream & os) const
+{
+    debugmsg("relational printraw",LOGLEVEL_PRINT);
+    os << "RELATIONAL(";
+    lh.printraw(os);
+    os << ",";
+    rh.printraw(os);
+    os << ",";
+    switch (o) {
+    case equal:
+        os << "==";
+        break;
+    case not_equal:
+        os << "!=";
+        break;
+    case less:
+        os << "<";
+        break;
+    case less_or_equal:
+        os << "<=";
+        break;
+    case greater:
+        os << ">";
+        break;
+    case greater_or_equal:
+        os << ">=";
+        break;
+    default:
+        os << "(INVALID RELATIONAL OPERATOR)";
+    }
+    os << ")";
+}
+
+void matrix::printraw(ostream & os) const
+{
+    debugmsg("matrix printraw",LOGLEVEL_PRINT);
+    os << "matrix(" << row << "," << col <<",";
+    for (int r=0; r<row-1; ++r) {
+        os << "(";
+        for (int c=0; c<col-1; ++c) {
+            os << m[r*col+c] << ",";
+        }
+        os << m[col*(r-1)-1] << "),";
+    }
+    os << "(";
+    for (int c=0; c<col-1; ++c) {
+        os << m[(row-1)*col+c] << ",";
+    }
+    os << m[row*col-1] << "))";
+}
diff --git a/ginac/printtree.cpp b/ginac/printtree.cpp
new file mode 100644 (file)
index 0000000..8188198
--- /dev/null
@@ -0,0 +1,149 @@
+/** @file printtree.cpp
+ *
+ * print in tree- (indented-) form, so developers can have a look at the
+ * underlying structure. */
+
+#include <iostream>
+#include <math.h>
+
+#include "ginac.h"
+
+void ex::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("ex printtree",LOGLEVEL_PRINT);
+    ASSERT(bp!=0);
+    // os << "refcount=" << bp->refcount << " ";
+    bp->printtree(os,indent);
+}
+
+void ex::dbgprinttree(void) const
+{
+    debugmsg("ex dbgprinttree",LOGLEVEL_PRINT);
+    ASSERT(bp!=0);
+    bp->dbgprinttree();
+}
+
+void basic::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("basic printtree",LOGLEVEL_PRINT);
+    os << string(indent,' ') << "type=" << typeid(*this).name()
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags
+       << ", nops=" << nops() << endl;
+    for (int i=0; i<nops(); ++i) {
+        op(i).printtree(os,indent+delta_indent);
+    }
+}
+
+void basic::dbgprinttree(void) const
+{
+    printtree(cerr,0);
+}
+
+void numeric::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("numeric printtree", LOGLEVEL_PRINT);
+    // We are cheating here, because we don't want to include the underlying
+    // bignum package's headers again, so we use ostream::operator<<(numeric):
+    os << string(indent,' ');
+    (*this).print(os);
+    os << " (numeric): "
+       << "hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void symbol::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("symbol printtree",LOGLEVEL_PRINT);
+    os << string(indent,' ') << name << " (symbol): "
+       << "serial=" << serial
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void power::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("power printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "power: "
+       << "hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+    basis.printtree(os,indent+delta_indent);
+    exponent.printtree(os,indent+delta_indent);
+}
+
+void expairseq::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("expairseq printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "type=" << typeid(*this).name()
+       << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags
+       << ", nops=" << nops() << endl;
+    for (unsigned i=0; i<seq.size(); ++i) {
+        seq[i].rest.printtree(os,indent+delta_indent);
+        seq[i].coeff.printtree(os,indent+delta_indent);
+        if (i!=seq.size()-1) {
+            os << string(indent+delta_indent,' ') << "-----" << endl;
+        }
+    }
+    if (!overall_coeff.is_equal(default_overall_coeff())) {
+        os << string(indent+delta_indent,' ') << "-----" << endl;
+        os << string(indent+delta_indent,' ') << "overall_coeff" << endl;
+        overall_coeff.printtree(os,indent+delta_indent);
+    }
+    os << string(indent+delta_indent,' ') << "=====" << endl;
+#ifdef EXPAIRSEQ_USE_HASHTAB
+    os << string(indent+delta_indent,' ')
+       << "hashtab size " << hashtabsize << endl;
+    if (hashtabsize==0) return;
+#define MAXCOUNT 5
+    unsigned count[MAXCOUNT+1];
+    for (int i=0; i<MAXCOUNT+1; ++i) count[i]=0;
+    unsigned this_bin_fill;
+    unsigned cum_fill_sq=0;
+    unsigned cum_fill=0;
+    for (unsigned i=0; i<hashtabsize; ++i) {
+        this_bin_fill=0;
+        if (hashtab[i].size()>0) {
+            os << string(indent+delta_indent,' ') 
+               << "bin " << i << " with entries ";
+            for (epplist::const_iterator it=hashtab[i].begin();
+                 it!=hashtab[i].end(); ++it) {
+                os << *it-seq.begin() << " ";
+                this_bin_fill++;
+            }
+            os << endl;
+            cum_fill += this_bin_fill;
+            cum_fill_sq += this_bin_fill*this_bin_fill;
+        }
+        if (this_bin_fill<MAXCOUNT) {
+            ++count[this_bin_fill];
+        } else {
+            ++count[MAXCOUNT];
+        }
+    }
+    unsigned fact=1;
+    double cum_prob=0;
+    double lambda=(1.0*seq.size())/hashtabsize;
+    for (int k=0; k<MAXCOUNT; ++k) {
+        if (k>0) fact *= k;
+        double prob=pow(lambda,k)/fact*exp(-lambda);
+        cum_prob += prob;
+        os << string(indent+delta_indent,' ') << "bins with " << k << " entries: "
+           << int(1000.0*count[k]/hashtabsize)/10.0 << "% (expected: "
+           << int(prob*1000)/10.0 << ")" << endl;
+    }
+    os << string(indent+delta_indent,' ') << "bins with more entries: "
+       << int(1000.0*count[MAXCOUNT]/hashtabsize)/10.0 << "% (expected: "
+       << int((1-cum_prob)*1000)/10.0 << ")" << endl;
+    
+    os << string(indent+delta_indent,' ') << "variance: "
+       << 1.0/hashtabsize*cum_fill_sq-(1.0/hashtabsize*cum_fill)*(1.0/hashtabsize*cum_fill)
+       << endl;
+    os << string(indent+delta_indent,' ') << "average fill: "
+       << (1.0*cum_fill)/hashtabsize
+       << " (should be equal to " << (1.0*seq.size())/hashtabsize << ")" << endl;
+#endif // def EXPAIRSEQ_USE_HASHTAB
+}
+
diff --git a/ginac/relational.cpp b/ginac/relational.cpp
new file mode 100644 (file)
index 0000000..252d8b3
--- /dev/null
@@ -0,0 +1,244 @@
+/** @file relational.cpp
+ *
+ *  Implementation of relations between expressions */
+
+#include <stdexcept>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+relational::relational() : basic(TINFO_RELATIONAL)
+{
+    debugmsg("relational default constructor",LOGLEVEL_CONSTRUCT);
+}
+
+relational::~relational()
+{
+    debugmsg("relational destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+relational::relational(relational const & other)
+{
+    debugmsg("relational copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+relational const & relational::operator=(relational const & other)
+{
+    debugmsg("relational operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void relational::copy(relational const & other)
+{
+    basic::copy(other);
+    lh=other.lh;
+    rh=other.rh;
+    o=other.o;
+}
+
+void relational::destroy(bool call_parent)
+{
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// public
+
+relational::relational(ex const & lhs, ex const & rhs, operators oper) : basic(TINFO_RELATIONAL)
+{
+    debugmsg("relational constructor ex,ex,operator",LOGLEVEL_CONSTRUCT);
+    lh=lhs;
+    rh=rhs;
+    o=oper;
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * relational::duplicate() const
+{
+    debugmsg("relational duplicate",LOGLEVEL_DUPLICATE);
+    return new relational(*this);
+}
+
+bool relational::info(unsigned inf) const
+{
+    switch (inf) {
+    case info_flags::relation:
+        return 1;
+    case info_flags::relation_equal:
+        return o==equal;
+    case info_flags::relation_not_equal:
+        return o==not_equal;
+    case info_flags::relation_less:
+        return o==less;
+    case info_flags::relation_less_or_equal:
+        return o==less_or_equal;
+    case info_flags::relation_greater:
+        return o==greater;
+    case info_flags::relation_greater_or_equal:
+        return o==greater_or_equal;
+    }
+    return 0;
+}
+
+int relational::nops() const
+{
+    return 2;
+}
+
+ex & relational::let_op(int const i)
+{
+    ASSERT(i>=0);
+    ASSERT(i<2);
+
+    return i==0 ? lh : rh;
+}
+    
+ex relational::eval(int level) const
+{
+    if (level==1) {
+        return this->hold();
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    return (new relational(lh.eval(level-1),rh.eval(level-1),o))->
+            setflag(status_flags::dynallocated  |
+                    status_flags::evaluated );
+}
+
+ex relational::evalf(int level) const
+{
+    if (level==1) {
+        return *this;
+    }
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    return (new relational(lh.eval(level-1),rh.eval(level-1),o))->
+            setflag(status_flags::dynallocated);
+}
+
+ex relational::simplify_ncmul(exvector const & v) const
+{
+    return lh.simplify_ncmul(v);
+}
+
+// protected
+
+int relational::compare_same_type(basic const & other) const
+{
+    ASSERT(is_exactly_of_type(other, relational));
+    relational const & oth=static_cast<relational const &>(const_cast<basic &>(other));
+    
+    int cmpval;
+    
+    if (o == oth.o) {
+        cmpval=lh.compare(oth.lh);
+        if (cmpval==0) {
+            return rh.compare(oth.rh);
+        } else {
+            return cmpval;
+        }
+    }
+    if (o<oth.o) {
+        return -1;
+    } else {
+        return 1;
+    }
+}
+
+unsigned relational::return_type(void) const
+{
+    ASSERT(lh.return_type()==rh.return_type());
+    return lh.return_type();
+}
+   
+unsigned relational::return_type_tinfo(void) const
+{
+    ASSERT(lh.return_type_tinfo()==rh.return_type_tinfo());
+    return lh.return_type_tinfo();
+}
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+#include <iostream>
+
+relational::operator bool() const
+{
+    // please note that (a<b) == false does not imply (a>=b) == true
+    // a false result means the comparison is either false or undecidable
+    // (except for !=, where true means unequal or undecidable)
+    ex df=lh-rh;
+    if (!is_ex_exactly_of_type(df,numeric)) {
+        return o==not_equal ? true : false; // cannot decide on non-numerical results
+    }
+    int cmpval=ex_to_numeric(df).compare(numZERO());
+    switch (o) {
+    case equal:
+        return cmpval==0;
+        break;
+    case not_equal:
+        return cmpval!=0;
+        break;
+    case less:
+        return cmpval<0;
+        break;
+    case less_or_equal:
+        return cmpval<=0;
+        break;
+    case greater:
+        return cmpval>0;
+        break;
+    case greater_or_equal:
+        return cmpval>=0;
+        break;
+    default:
+        throw(std::logic_error("invalid relational operator"));
+    }
+    return 0;
+}
+
+//////////
+// static member variables
+//////////
+
+// protected
+
+unsigned relational::precedence=20;
+
+//////////
+// global constants
+//////////
+
+const relational some_relational;
+type_info const & typeid_relational=typeid(some_relational);
+
diff --git a/ginac/relational.h b/ginac/relational.h
new file mode 100644 (file)
index 0000000..34c592c
--- /dev/null
@@ -0,0 +1,85 @@
+/** @file relational.h
+ *
+ *  Interface to relations between expressions. */
+
+#ifndef _RELATIONAL_H_
+#define _RELATIONAL_H_
+
+class relational;
+
+#include "basic.h"
+
+/** This class holds a relation consisting of two expressions and a logical
+ *  relation between them. */
+class relational : public basic
+{
+
+// types
+public:
+    enum operators { equal,
+           not_equal,
+           less,
+           less_or_equal,
+           greater,
+           greater_or_equal
+    };
+    
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    relational();
+    ~relational();
+    relational(relational const & other);
+    relational const & operator=(relational const & other);
+protected:
+    void copy(relational const & other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    relational(ex const & lhs, ex const & rhs, operators oper=equal);
+    
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+    int nops() const;
+    ex & let_op(int const i);
+    ex eval(int level=0) const;
+    ex evalf(int level=0) const;
+    ex simplify_ncmul(exvector const & v) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+
+    // new virtual functions which can be overridden by derived classes
+    // none
+
+    // non-virtual functions in this class
+public:
+    operator bool(void) const;
+    
+// member variables
+    
+protected:
+    ex lh;
+    ex rh;
+    operators o;
+    static unsigned precedence;
+};
+
+// global constants
+
+extern const relational some_relational;
+extern type_info const & typeid_relational;
+
+#define ex_to_relational(X) static_cast<relational const &>(*(X).bp)
+
+#endif // ndef _RELATIONAL_H_
+
+
diff --git a/ginac/series.cpp b/ginac/series.cpp
new file mode 100644 (file)
index 0000000..9daf656
--- /dev/null
@@ -0,0 +1,610 @@
+/** @file series.cpp
+ *
+ *  Implementation of class for extended truncated power-series and
+ *  methods for series expansion. */
+
+#include "ginac.h"
+
+
+/*
+ *  Default constructor, destructor, copy constructor, assignment operator and helpers
+ */
+
+series::series() : basic(TINFO_SERIES)
+{
+    debugmsg("series default constructor", LOGLEVEL_CONSTRUCT);
+}
+
+series::~series()
+{
+    debugmsg("series destructor", LOGLEVEL_DESTRUCT);
+    destroy(false);
+}
+
+series::series(series const &other)
+{
+    debugmsg("series copy constructor", LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+series const &series::operator=(series const & other)
+{
+    debugmsg("series operator=", LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(true);
+        copy(other);
+    }
+    return *this;
+}
+
+void series::copy(series const &other)
+{
+    inherited::copy(other);
+    seq = other.seq;
+    var = other.var;
+    point = other.point;
+}
+
+void series::destroy(bool call_parent)
+{
+    if (call_parent)
+        inherited::destroy(call_parent);
+}
+
+
+/*
+ *  Other constructors
+ */
+
+/** Construct series from a vector of coefficients and powers.
+ *  expair.rest holds the coefficient, expair.coeff holds the power.
+ *  The powers must be integers (positive or negative) and in ascending order;
+ *  the last coefficient can be Order(exONE()) to represent a truncated,
+ *  non-terminating series.
+ *
+ *  @param var_  series variable (must hold a symbol)
+ *  @param point_  expansion point
+ *  @param ops_  vector of {coefficient, power} pairs (coefficient must not be zero)
+ *  @return newly constructed series */
+series::series(ex const &var_, ex const &point_, epvector const &ops_)
+    : basic(TINFO_SERIES), seq(ops_), var(var_), point(point_)
+{
+    debugmsg("series constructor from ex,ex,epvector", LOGLEVEL_CONSTRUCT);
+    ASSERT(is_ex_exactly_of_type(var_, symbol));
+}
+
+
+/*
+ *  Functions overriding virtual functions from base classes
+ */
+
+basic *series::duplicate() const
+{
+    debugmsg("series duplicate", LOGLEVEL_DUPLICATE);
+    return new series(*this);
+}
+
+// Highest degree of variable
+int series::degree(symbol const &s) const
+{
+    if (var == s) {
+        // Return last exponent
+        if (seq.size())
+            return ex_to_numeric((*(seq.end() - 1)).coeff).to_int();
+        else
+            return 0;
+    } else {
+        epvector::const_iterator it = seq.begin(), itend = seq.end();
+        if (it == itend)
+            return 0;
+        int max_pow = INT_MIN;
+        while (it != itend) {
+            int pow = it->rest.degree(s);
+            if (pow > max_pow)
+                max_pow = pow;
+            it++;
+        }
+        return max_pow;
+    }
+}
+
+// Lowest degree of variable
+int series::ldegree(symbol const &s) const
+{
+    if (var == s) {
+        // Return first exponent
+        if (seq.size())
+            return ex_to_numeric((*(seq.begin())).coeff).to_int();
+        else
+            return 0;
+    } else {
+        epvector::const_iterator it = seq.begin(), itend = seq.end();
+        if (it == itend)
+            return 0;
+        int min_pow = INT_MAX;
+        while (it != itend) {
+            int pow = it->rest.ldegree(s);
+            if (pow < min_pow)
+                min_pow = pow;
+            it++;
+        }
+        return min_pow;
+    }
+}
+
+// Coefficient of variable
+ex series::coeff(symbol const &s, int n) const
+{
+    if (var == s) {
+        epvector::const_iterator it = seq.begin(), itend = seq.end();
+        while (it != itend) {
+            int pow = ex_to_numeric(it->coeff).to_int();
+            if (pow == n)
+                return it->rest;
+            if (pow > n)
+                return exZERO();
+            it++;
+        }
+        return exZERO();
+    } else
+        return convert_to_poly().coeff(s, n);
+}
+
+ex series::eval(int level) const
+{
+    if (level == 1)
+        return this->hold();
+
+    // Construct a new series with evaluated coefficients
+    epvector new_seq;
+    new_seq.reserve(seq.size());
+    epvector::const_iterator it = seq.begin(), itend = seq.end();
+    while (it != itend) {
+        new_seq.push_back(expair(it->rest.eval(level-1), it->coeff));
+        it++;
+    }
+    return (new series(var, point, new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
+}
+
+ex series::evalf(int level) const
+{
+    return convert_to_poly().evalf(level);
+}
+
+
+/*
+ *  Construct expression (polynomial) out of series
+ */
+
+/** Convert a series object to an ordinary polynomial.
+ *
+ *  @param no_order flag: discard higher order terms */
+ex series::convert_to_poly(bool no_order) const
+{
+    ex e;
+    epvector::const_iterator it = seq.begin(), itend = seq.end();
+
+    while (it != itend) {
+        if (is_order_function(it->rest)) {
+            if (!no_order)
+                e += Order(power(var - point, it->coeff));
+        } else
+            e += it->rest * power(var - point, it->coeff);
+        it++;
+    }
+    return e;
+}
+
+
+/*
+ *  Implementation of series expansion
+ */
+
+/** Default implementation of ex::series(). This performs Taylor expansion.
+ *  @see ex::series */
+ex basic::series(symbol const & s, ex const & point, int order) const
+{
+    epvector seq;
+    numeric fac(1);
+    ex deriv = *this;
+    ex coeff = deriv.subs(s == point);
+    if (!coeff.is_zero())
+        seq.push_back(expair(coeff, numeric(0)));
+
+    int n;
+    for (n=1; n<order; n++) {
+        fac = fac.mul(numeric(n));
+        deriv = deriv.diff(s).expand();
+        if (deriv.is_zero()) {
+            // Series terminates
+            return series::series(s, point, seq);
+        }
+        coeff = power(fac, -1) * deriv.subs(s == point);
+        if (!coeff.is_zero())
+            seq.push_back(expair(coeff, numeric(n)));
+    }
+
+    // Higher-order terms, if present
+    deriv = deriv.diff(s);
+    if (!deriv.is_zero())
+        seq.push_back(expair(Order(exONE()), numeric(n)));
+    return series::series(s, point, seq);
+}
+
+
+/** Add one series object to another, producing a series object that represents
+ *  the sum.
+ *
+ *  @param other  series object to add with
+ *  @return the sum as a series */
+ex series::add_series(const series &other) const
+{
+    // Adding two series with different variables or expansion points
+    // results in an empty (constant) series 
+    if (!is_compatible_to(other)) {
+        epvector nul;
+        nul.push_back(expair(Order(exONE()), exZERO()));
+        return series(var, point, nul);
+    }
+
+    // Series addition
+    epvector new_seq;
+    epvector::const_iterator a = seq.begin();
+    epvector::const_iterator b = other.seq.begin();
+    epvector::const_iterator a_end = seq.end();
+    epvector::const_iterator b_end = other.seq.end();
+    int pow_a = INT_MAX, pow_b = INT_MAX;
+    for (;;) {
+        // If a is empty, fill up with elements from b and stop
+        if (a == a_end) {
+            while (b != b_end) {
+                new_seq.push_back(*b);
+                b++;
+            }
+            break;
+        } else
+            pow_a = ex_to_numeric((*a).coeff).to_int();
+
+        // If b is empty, fill up with elements from a and stop
+        if (b == b_end) {
+            while (a != a_end) {
+                new_seq.push_back(*a);
+                a++;
+            }
+            break;
+        } else
+            pow_b = ex_to_numeric((*b).coeff).to_int();
+
+        // a and b are non-empty, compare powers
+        if (pow_a < pow_b) {
+            // a has lesser power, get coefficient from a
+            new_seq.push_back(*a);
+            if (is_order_function((*a).rest))
+                break;
+            a++;
+        } else if (pow_b < pow_a) {
+            // b has lesser power, get coefficient from b
+            new_seq.push_back(*b);
+            if (is_order_function((*b).rest))
+                break;
+            b++;
+        } else {
+            // Add coefficient of a and b
+            if (is_order_function((*a).rest) || is_order_function((*b).rest)) {
+                new_seq.push_back(expair(Order(exONE()), (*a).coeff));
+                break;  // Order term ends the sequence
+            } else {
+                ex sum = (*a).rest + (*b).rest;
+                if (!(sum == exZERO()))
+                    new_seq.push_back(expair(sum, numeric(pow_a)));
+                a++;
+                b++;
+            }
+        }
+    }
+    return series(var, point, new_seq);
+}
+
+
+/** Implementation of ex::series() for sums. This performs series addition when
+ *  adding series objects.
+ *  @see ex::series */
+/*
+ex add::series(symbol const & s, ex const & point, int order) const
+{
+    ex acc; // Series accumulator
+
+    // Get first term
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    if (it != itend) {
+        if (is_ex_exactly_of_type(it->rest, series))
+            acc = it->rest;
+        else
+            acc = it->rest.series(s, point, order);
+        if (!it->coeff.is_equal(exONE()))
+            acc = ex_to_series(acc).mul_const(ex_to_numeric(it->coeff));
+        it++;
+    }
+
+    // Add remaining terms
+    for (; it!=itend; it++) {
+        ex op;
+        if (is_ex_exactly_of_type(it->rest, series))
+            op = it->rest;
+        else
+            op = it->rest.series(s, point, order);
+        if (!it->coeff.is_equal(exONE()))
+            op = ex_to_series(op).mul_const(ex_to_numeric(it->coeff));
+
+        // Series addition
+        acc = ex_to_series(acc).add_series(ex_to_series(op));
+    }
+    return acc;
+}
+*/
+ex add::series(symbol const & s, ex const & point, int order) const
+{
+    ex acc; // Series accumulator
+
+    // Get first term from overall_coeff
+    acc = overall_coeff.series(s,point,order);
+
+    // Add remaining terms
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    for (; it!=itend; it++) {
+        ex op;
+        if (is_ex_exactly_of_type(it->rest, series))
+            op = it->rest;
+        else
+            op = it->rest.series(s, point, order);
+        if (!it->coeff.is_equal(exONE()))
+            op = ex_to_series(op).mul_const(ex_to_numeric(it->coeff));
+
+        // Series addition
+        acc = ex_to_series(acc).add_series(ex_to_series(op));
+    }
+    return acc;
+}
+
+
+/** Multiply a series object with a numeric constant, producing a series object
+ *  that represents the product.
+ *
+ *  @param other  constant to multiply with
+ *  @return the product as a series */
+ex series::mul_const(const numeric &other) const
+{
+    epvector new_seq;
+    new_seq.reserve(seq.size());
+
+    epvector::const_iterator it = seq.begin(), itend = seq.end();
+    while (it != itend) {
+        if (!is_order_function(it->rest))
+            new_seq.push_back(expair(it->rest * other, it->coeff));
+        else
+            new_seq.push_back(*it);
+        it++;
+    }
+    return series(var, point, new_seq);
+}
+
+
+/** Multiply one series object to another, producing a series object that
+ *  represents the product.
+ *
+ *  @param other  series object to multiply with
+ *  @return the product as a series */
+ex series::mul_series(const series &other) const
+{
+    // Multiplying two series with different variables or expansion points
+    // results in an empty (constant) series 
+    if (!is_compatible_to(other)) {
+        epvector nul;
+        nul.push_back(expair(Order(exONE()), exZERO()));
+        return series(var, point, nul);
+    }
+
+    // Series multiplication
+    epvector new_seq;
+
+    const symbol *s = static_cast<symbol *>(var.bp);
+    int a_max = degree(*s);
+    int b_max = other.degree(*s);
+    int a_min = ldegree(*s);
+    int b_min = other.ldegree(*s);
+    int cdeg_min = a_min + b_min;
+    int cdeg_max = a_max + b_max;
+
+    int higher_order_a = INT_MAX;
+    int higher_order_b = INT_MAX;
+    if (is_order_function(coeff(*s, a_max)))
+        higher_order_a = a_max + b_min;
+    if (is_order_function(other.coeff(*s, b_max)))
+        higher_order_b = b_max + a_min;
+    int higher_order_c = min(higher_order_a, higher_order_b);
+    if (cdeg_max >= higher_order_c)
+        cdeg_max = higher_order_c - 1;
+
+    for (int cdeg=cdeg_min; cdeg<=cdeg_max; cdeg++) {
+        ex co = exZERO();
+        // c(i)=a(0)b(i)+...+a(i)b(0)
+        for (int i=a_min; cdeg-i>=b_min; i++) {
+            ex a_coeff = coeff(*s, i);
+            ex b_coeff = other.coeff(*s, cdeg-i);
+            if (!is_order_function(a_coeff) && !is_order_function(b_coeff))
+                co += coeff(*s, i) * other.coeff(*s, cdeg-i);
+        }
+        if (!co.is_zero())
+            new_seq.push_back(expair(co, numeric(cdeg)));
+    }
+    if (higher_order_c < INT_MAX)
+        new_seq.push_back(expair(Order(exONE()), numeric(higher_order_c)));
+    return series::series(var, point, new_seq);
+}
+
+
+/** Implementation of ex::series() for product. This performs series multiplication when multiplying series.
+ *  @see ex::series */
+/*
+ex mul::series(symbol const & s, ex const & point, int order) const
+{
+    ex acc; // Series accumulator
+
+    // Get first term
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    if (it != itend) {
+        if (is_ex_exactly_of_type(it->rest, series))
+            acc = it->rest;
+        else
+            acc = it->rest.series(s, point, order);
+        if (!it->coeff.is_equal(exONE()))
+            acc = ex_to_series(acc).power_const(ex_to_numeric(it->coeff), order);
+        it++;
+    }
+
+    // Multiply with remaining terms
+    for (; it!=itend; it++) {
+        ex op = it->rest;
+        if (op.info(info_flags::numeric)) {
+            // series * const (special case, faster)
+            ex f = power(op, it->coeff);
+            acc = ex_to_series(acc).mul_const(ex_to_numeric(f));
+            continue;
+        } else if (!is_ex_exactly_of_type(op, series))
+            op = op.series(s, point, order);
+        if (!it->coeff.is_equal(exONE()))
+            op = ex_to_series(op).power_const(ex_to_numeric(it->coeff), order);
+
+        // Series multiplication
+        acc = ex_to_series(acc).mul_series(ex_to_series(op));
+    }
+    return acc;
+}
+*/
+
+ex mul::series(symbol const & s, ex const & point, int order) const
+{
+    ex acc; // Series accumulator
+
+    // Get first term from overall_coeff
+    acc = overall_coeff.series(s, point, order);
+
+    // Multiply with remaining terms
+    epvector::const_iterator it = seq.begin();
+    epvector::const_iterator itend = seq.end();
+    for (; it!=itend; it++) {
+        ex op = it->rest;
+        if (op.info(info_flags::numeric)) {
+            // series * const (special case, faster)
+            ex f = power(op, it->coeff);
+            acc = ex_to_series(acc).mul_const(ex_to_numeric(f));
+            continue;
+        } else if (!is_ex_exactly_of_type(op, series))
+            op = op.series(s, point, order);
+        if (!it->coeff.is_equal(exONE()))
+            op = ex_to_series(op).power_const(ex_to_numeric(it->coeff), order);
+
+        // Series multiplication
+        acc = ex_to_series(acc).mul_series(ex_to_series(op));
+    }
+    return acc;
+}
+
+
+/** Compute the p-th power of a series.
+ *
+ *  @param p  power to compute
+ *  @param deg  truncation order of series calculation */
+ex series::power_const(const numeric &p, int deg) const
+{
+    int i;
+    const symbol *s = static_cast<symbol *>(var.bp);
+    int ldeg = ldegree(*s);
+
+    // Calculate coefficients of powered series
+    exvector co;
+    co.reserve(deg);
+    ex co0;
+    co.push_back(co0 = power(coeff(*s, ldeg), p));
+    bool all_sums_zero = true;
+    for (i=1; i<deg; i++) {
+        ex sum = exZERO();
+        for (int j=1; j<=i; j++) {
+            ex c = coeff(*s, j + ldeg);
+            if (is_order_function(c)) {
+                co.push_back(Order(exONE()));
+                break;
+            } else
+                sum += (p * j - (i - j)) * co[i - j] * c;
+        }
+        if (!sum.is_zero())
+            all_sums_zero = false;
+        co.push_back(co0 * sum / numeric(i));
+    }
+
+    // Construct new series (of non-zero coefficients)
+    epvector new_seq;
+    bool higher_order = false;
+    for (i=0; i<deg; i++) {
+        if (!co[i].is_zero())
+            new_seq.push_back(expair(co[i], numeric(i) + p * ldeg));
+        if (is_order_function(co[i])) {
+            higher_order = true;
+            break;
+        }
+    }
+    if (!higher_order && !all_sums_zero)
+        new_seq.push_back(expair(Order(exONE()), numeric(deg) + p * ldeg));
+    return series::series(var, point, new_seq);
+}
+
+
+/** Implementation of ex::series() for powers. This performs Laurent expansion
+ *  of reciprocals of series at singularities.
+ *  @see ex::series */
+ex power::series(symbol const & s, ex const & point, int order) const
+{
+    ex e;
+    if (!is_ex_exactly_of_type(basis, series)) {
+        // Basis is not a series, may there be a singulary?
+        if (!exponent.info(info_flags::negint))
+            return basic::series(s, point, order);
+
+        // Expression is of type something^(-int), check for singularity
+        if (!basis.subs(s == point).is_zero())
+            return basic::series(s, point, order);
+
+        // Singularity encountered, expand basis into series
+        e = basis.series(s, point, order);
+    } else {
+        // Basis is a series
+        e = basis;
+    }
+
+    // Power e
+    return ex_to_series(e).power_const(ex_to_numeric(exponent), order);
+}
+
+
+/** Compute the truncated series expansion of an expression.
+ *  This function returns an expression containing an object of class series to
+ *  represent the series. If the series does not terminate within the given
+ *  truncation order, the last term of the series will be an order term.
+ *
+ *  @param s  expansion variable
+ *  @param point  expansion point
+ *  @param order  truncation order of series calculations
+ *  @return an expression holding a series object */
+ex ex::series(symbol const &s, ex const &point, int order) const
+{
+    ASSERT(bp!=0);
+    return bp->series(s, point, order);
+}
+
+
+// Global constants
+const series some_series;
+type_info const & typeid_series = typeid(some_series);
diff --git a/ginac/series.h b/ginac/series.h
new file mode 100644 (file)
index 0000000..89b9126
--- /dev/null
@@ -0,0 +1,77 @@
+/** @file series.h
+ *
+ *  Interface to class for extended truncated power series. */
+
+#ifndef _SERIES_H_
+#define _SERIES_H_
+
+#include "basic.h"
+#include "ex.h"
+#include "expairseq.h"
+#include "symbol.h"
+
+
+/** This class holds a extended truncated power series (positive and negative
+ *  integer powers). It consists of expression coefficients (only non-zero
+ *  coefficients are stored), an expansion variable and an expansion point.
+ *  Other classes must provide members to convert into this type. */
+class series : public basic
+{
+    typedef basic inherited;
+
+    // default constructor, destructor, copy constructor, assignment operator and helpers
+public:
+    series();
+    ~series();
+    series(series const &other);
+    series const &operator=(series const &other);
+protected:
+    void copy(series const &other);
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    series(ex const &var_, ex const &point_, epvector const &ops_);
+
+    // functions overriding virtual functions from base classes
+public:
+    basic *duplicate() const;
+    void printraw(ostream &os) const;
+    void print(ostream &os, unsigned upper_precedence=0) const;
+    int degree(symbol const &s) const;
+    int ldegree(symbol const &s) const;
+    ex coeff(symbol const &s, int const n=1) const;
+    ex eval(int level=0) const;
+    ex evalf(int level=0) const;
+    ex diff(symbol const & s) const;
+    ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+
+    // non-virtual functions in this class
+public:
+    ex convert_to_poly(bool no_order = false) const;
+    bool is_compatible_to(const series &other) const {return var.compare(other.var) == 0 && point.compare(other.point) == 0;}
+    bool is_zero(void) const {return seq.size() == 0;}
+    ex add_series(const series &other) const;
+    ex mul_const(const numeric &other) const;
+    ex mul_series(const series &other) const;
+    ex power_const(const numeric &p, int deg) const;
+
+protected:
+    /** Vector of {coefficient, power} pairs */
+    epvector seq;
+
+    /** Series variable (holds a symbol) */
+    ex var;
+
+    /** Expansion point */
+    ex point;
+};
+
+// global constants
+extern const series some_series;
+extern type_info const & typeid_series;
+
+#define ex_to_series(X) (static_cast<class series const &>(*(X).bp))
+#define series_to_poly(X) (static_cast<series const &>(*(X).bp).convert_to_poly(true))
+
+#endif
diff --git a/ginac/simp_lor.cpp b/ginac/simp_lor.cpp
new file mode 100644 (file)
index 0000000..32d05b0
--- /dev/null
@@ -0,0 +1,493 @@
+/** @file simp_lor.cpp
+ *
+ *  Implementation of GiNaC's simp_lor objects.
+ *  No real implementation yet, to be done.     */
+
+#include <string>
+#include <list>
+#include <algorithm>
+#include <iostream>
+#include <stdexcept>
+#include <map>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+simp_lor::simp_lor() : type(invalid)
+{
+    debugmsg("simp_lor default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_SIMP_LOR;
+}
+
+simp_lor::~simp_lor()
+{
+    debugmsg("simp_lor destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+simp_lor::simp_lor(simp_lor const & other)
+{
+    debugmsg("simp_lor copy constructor",LOGLEVEL_CONSTRUCT);
+    copy (other);
+}
+
+simp_lor const & simp_lor::operator=(simp_lor const & other)
+{
+    debugmsg("simp_lor operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void simp_lor::copy(simp_lor const & other)
+{
+    indexed::copy(other);
+    type=other.type;
+    name=other.name;
+}
+
+void simp_lor::destroy(bool call_parent)
+{
+    if (call_parent) {
+        indexed::destroy(call_parent);
+    }
+}
+
+//////////
+// other constructors
+//////////
+
+// protected
+
+simp_lor::simp_lor(simp_lor_types const t) : type(t)
+{
+    debugmsg("simp_lor constructor from simp_lor_types",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_SIMP_LOR;
+}
+
+simp_lor::simp_lor(simp_lor_types const t, ex const & i1, ex const & i2) :
+    indexed(i1,i2), type(t)
+{
+    debugmsg("simp_lor constructor from simp_lor_types,ex,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_SIMP_LOR;
+    ASSERT(all_of_type_lorentzidx());
+}
+
+simp_lor::simp_lor(simp_lor_types const t, string const & n, ex const & i1) :
+    indexed(i1), type(t), name(n)
+{
+    debugmsg("simp_lor constructor from simp_lor_types,string,ex",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_SIMP_LOR;
+    ASSERT(all_of_type_lorentzidx());
+}
+
+simp_lor::simp_lor(simp_lor_types const t, string const & n, exvector const & iv) :
+    indexed(iv), type(t), name(n)
+{
+    debugmsg("simp_lor constructor from simp_lor_types,string,exvector",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_SIMP_LOR;
+    ASSERT(all_of_type_lorentzidx());
+}
+
+simp_lor::simp_lor(simp_lor_types const t, string const & n, exvector * ivp) :
+    indexed(ivp), type(t), name(n)
+{
+    debugmsg("simp_lor constructor from simp_lor_types,string,exvector*",LOGLEVEL_CONSTRUCT);
+    tinfo_key=TINFO_SIMP_LOR;
+    ASSERT(all_of_type_lorentzidx());
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * simp_lor::duplicate() const
+{
+    debugmsg("simp_lor duplicate",LOGLEVEL_DUPLICATE);
+    return new simp_lor(*this);
+}
+
+void simp_lor::printraw(ostream & os) const
+{
+    debugmsg("simp_lor printraw",LOGLEVEL_PRINT);
+    os << "simp_lor(type=" << (unsigned)type
+       << ",name=" << name << ",indices=";
+    printrawindices(os);
+    os << ",hash=" << hashvalue << ",flags=" << flags << ")";
+}
+
+void simp_lor::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("simp_lor printtree",LOGLEVEL_PRINT);
+    os << string(indent,' ') << "simp_lor object: "
+       << "type=" << (unsigned)type
+       << ", name=" << name << ", ";
+    os << seq.size() << " indices" << endl;
+    printtreeindices(os,indent);
+    os << string(indent,' ') << "hash=" << hashvalue
+       << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void simp_lor::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("simp_lor print",LOGLEVEL_PRINT);
+    switch (type) {
+    case simp_lor_g:
+        os << "g";
+        break;
+    case simp_lor_vec:
+        os << name;
+        break;
+    case invalid:
+    default:
+        os << "INVALID_SIMP_LOR_OBJECT";
+        break;
+    }
+    printindices(os);
+}
+
+void simp_lor::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("simp_lor print csrc",LOGLEVEL_PRINT);
+    print(os,upper_precedence);
+}
+
+bool simp_lor::info(unsigned inf) const
+{
+    return indexed::info(inf);
+}
+
+ex simp_lor::eval(int level) const
+{
+    if (type==simp_lor_g) {
+        // canonicalize indices
+        exvector iv=seq;
+        int sig=canonicalize_indices(iv,false); // symmetric
+        if (sig!=INT_MAX) {
+            // something has changed while sorting indices, more evaluations later
+            if (sig==0) return exZERO();
+            return ex(sig)*simp_lor(type,name,iv);
+        }
+        lorentzidx const & idx1=ex_to_lorentzidx(seq[0]);
+        lorentzidx const & idx2=ex_to_lorentzidx(seq[1]);
+        if ((!idx1.is_symbolic())&&(!idx2.is_symbolic())) {
+            // both indices are numeric
+            if ((idx1.get_value()==idx2.get_value())) {
+                // both on diagonal
+                if (idx1.get_value()==0) {
+                    // (0,0)
+                    return exONE();
+                } else {
+                    if (idx1.is_covariant()!=idx2.is_covariant()) {
+                        // (_i,~i) or (~i,_i), i=1..3
+                        return exONE();
+                    } else {
+                        // (_i,_i) or (~i,~i), i=1..3
+                        return exMINUSONE();
+                    }
+                }
+            } else {
+                // at least one off-diagonal
+                return exZERO();
+            }
+        } else if (idx1.is_symbolic() &&
+                   idx1.is_co_contra_pair(idx2)) {
+            return Dim()-idx1.get_dim_parallel_space();
+        }
+    }
+
+    return this->hold();
+}
+    
+// protected
+
+int simp_lor::compare_same_type(basic const & other) const
+{
+    ASSERT(other.tinfo() == TINFO_SIMP_LOR);
+    const simp_lor *o = static_cast<const simp_lor *>(&other);
+    if (type==o->type) {
+        if (name==o->name) {
+            return indexed::compare_same_type(other);
+        }
+        return name.compare(o->name);
+    }
+    return type < o->type ? -1 : 1;
+}
+
+bool simp_lor::is_equal_same_type(basic const & other) const
+{
+    ASSERT(other.tinfo() == TINFO_SIMP_LOR);
+    const simp_lor *o = static_cast<const simp_lor *>(&other);
+    if (type!=o->type) return false;
+    if (name!=o->name) return false;
+    return indexed::is_equal_same_type(other);
+}
+
+unsigned simp_lor::return_type(void) const
+{
+    return return_types::commutative;
+}
+   
+unsigned simp_lor::return_type_tinfo(void) const
+{
+    return tinfo_key;
+}
+
+ex simp_lor::thisexprseq(exvector const & v) const
+{
+    return simp_lor(type,name,v);
+}
+
+ex simp_lor::thisexprseq(exvector * vp) const
+{
+    return simp_lor(type,name,vp);
+}
+
+//////////
+// virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// protected
+
+bool simp_lor::all_of_type_lorentzidx(void) const
+{
+    // used only inside of ASSERTs
+    for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
+        if (!is_ex_of_type(*cit,lorentzidx)) return false;
+    }
+    return true;
+}
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const simp_lor some_simp_lor;
+type_info const & typeid_simp_lor=typeid(some_simp_lor);
+
+//////////
+// friend functions
+//////////
+
+simp_lor lor_g(ex const & mu, ex const & nu)
+{
+    return simp_lor(simp_lor::simp_lor_g,mu,nu);
+}
+
+simp_lor lor_vec(string const & n, ex const & mu)
+{
+    return simp_lor(simp_lor::simp_lor_vec,n,mu);
+}
+
+ex simplify_simp_lor_mul(ex const & m, scalar_products const & sp)
+{
+    ASSERT(is_ex_exactly_of_type(m,mul));
+    exvector v_contracted;
+
+    // collect factors in an exvector, store squares twice
+    int n=m.nops();
+    v_contracted.reserve(2*n);
+    for (int i=0; i<n; ++i) {
+        ex f=m.op(i);
+        if (is_ex_exactly_of_type(f,power)&&f.op(1)==2) {
+            v_contracted.push_back(f.op(0));
+            v_contracted.push_back(f.op(0));
+        } else {
+            v_contracted.push_back(f);
+       }
+    }
+
+    unsigned replacements;
+    bool something_changed=false;
+
+    exvector::iterator it=v_contracted.begin();
+    while (it!=v_contracted.end()) {
+        // process only lor_g objects
+        if (is_ex_exactly_of_type(*it,simp_lor) &&
+            (ex_to_simp_lor(*it).type==simp_lor::simp_lor_g)) {
+            simp_lor const & g=ex_to_simp_lor(*it);
+            ASSERT(g.seq.size()==2);
+            idx const & first_idx=ex_to_lorentzidx(g.seq[0]);
+            idx const & second_idx=ex_to_lorentzidx(g.seq[1]);
+            // g_{mu,mu} should have been contracted in simp_lor::eval()
+            ASSERT(!first_idx.is_equal(second_idx));
+            ex saved_g=*it; // save to restore it later
+
+            // try to contract first index
+            replacements=0;
+            if (first_idx.is_symbolic()) {
+                replacements = subs_index_in_exvector(v_contracted,
+                                   first_idx.toggle_covariant(),second_idx);
+                if (replacements==0) {
+                    // not contracted, restore g object
+                    *it=saved_g;
+                } else {
+                    // a contracted index should occur exactly once
+                    ASSERT(replacements==1);
+                    *it=exONE();
+                    something_changed=true;
+                }
+            }
+
+            // try second index only if first was not contracted
+            if ((replacements==0)&&(second_idx.is_symbolic())) {
+                // first index not contracted, *it is again the original g object
+                replacements = subs_index_in_exvector(v_contracted,
+                                   second_idx.toggle_covariant(),first_idx);
+                if (replacements==0) {
+                    // not contracted except in itself, restore g object
+                    *it=saved_g;
+                } else {
+                    // a contracted index should occur exactly once
+                    ASSERT(replacements==1);
+                    *it=exONE();
+                    something_changed=true;
+                }
+            }
+        }
+        ++it;
+    }
+
+    // process only lor_vec objects
+    bool jump_to_next=false;
+    exvector::iterator it1=v_contracted.begin();
+    while (it1!=v_contracted.end()-1) {
+        if (is_ex_exactly_of_type(*it1,simp_lor) && 
+            (ex_to_simp_lor(*it1).type==simp_lor::simp_lor_vec)) {
+            exvector::iterator it2=it1+1;
+            while ((it2!=v_contracted.end())&&!jump_to_next) {
+                if (is_ex_exactly_of_type(*it2,simp_lor) && 
+                    (ex_to_simp_lor(*it2).type==simp_lor::simp_lor_vec)) {
+                    simp_lor const & vec1=ex_to_simp_lor(*it1);
+                    simp_lor const & vec2=ex_to_simp_lor(*it2);
+                    ASSERT(vec1.seq.size()==1);
+                    ASSERT(vec2.seq.size()==1);
+                    lorentzidx const & idx1=ex_to_lorentzidx(vec1.seq[0]);
+                    lorentzidx const & idx2=ex_to_lorentzidx(vec2.seq[0]);
+                    if (idx1.is_symbolic() &&
+                        idx1.is_co_contra_pair(idx2) &&
+                        sp.is_defined(vec1,vec2)) {
+                        *it1=sp.evaluate(vec1,vec2);
+                        *it2=exONE();
+                        something_changed=true;
+                        jump_to_next=true;
+                    }
+                }
+                ++it2;
+            }
+            jump_to_next=false;
+        }
+        ++it1;
+    }
+    if (something_changed) {
+        return mul(v_contracted);
+    }
+    return m;
+}
+
+ex simplify_simp_lor(ex const & e, scalar_products const & sp)
+{
+    // all simplification is done on expanded objects
+    ex e_expanded=e.expand();
+
+    // simplification of sum=sum of simplifications
+    if (is_ex_exactly_of_type(e_expanded,add)) {
+        ex sum=exZERO();
+        for (int i=0; i<e_expanded.nops(); ++i) {
+            sum += simplify_simp_lor(e_expanded.op(i),sp);
+        }
+        return sum;
+    }
+
+    // simplification of commutative product=commutative product of simplifications
+    if (is_ex_exactly_of_type(e_expanded,mul)) {
+        return simplify_simp_lor_mul(e,sp);
+    }
+
+    // cannot do anything
+    return e_expanded;
+}
+
+ex Dim(void)
+{
+    static symbol * d=new symbol("dim");
+    return *d;
+}
+
+//////////
+// helper classes
+//////////
+
+void scalar_products::reg(simp_lor const & v1, simp_lor const & v2,
+                          ex const & sp)
+{
+    if (v1.compare_same_type(v2)>0) {
+        reg(v2,v1,sp);
+        return;
+    }
+    spm[make_key(v1,v2)]=sp;
+}
+
+bool scalar_products::is_defined(simp_lor const & v1, simp_lor const & v2) const
+{
+    if (v1.compare_same_type(v2)>0) {
+        return is_defined(v2,v1);
+    }
+    return spm.find(make_key(v1,v2))!=spm.end();
+}
+
+ex scalar_products::evaluate(simp_lor const & v1, simp_lor const & v2) const
+{
+    if (v1.compare_same_type(v2)>0) {
+        return evaluate(v2,v1);
+    }
+    return spm.find(make_key(v1,v2))->second;
+}
+
+void scalar_products::debugprint(void) const
+{
+    cerr << "map size=" << spm.size() << endl;
+    for (spmap::const_iterator cit=spm.begin(); cit!=spm.end(); ++cit) {
+        spmapkey const & k=(*cit).first;
+        cerr << "item key=((" << k.first.first
+             << "," << k.first.second << "),";
+        k.second.printraw(cerr);
+        cerr << ") value=" << (*cit).second << endl;
+    }
+}
+
+spmapkey scalar_products::make_key(simp_lor const & v1, simp_lor const & v2)
+{
+    ASSERT(v1.type==simp_lor::simp_lor_vec);
+    ASSERT(v2.type==simp_lor::simp_lor_vec);
+    lorentzidx anon=ex_to_lorentzidx(v1.seq[0]).create_anonymous_representative();
+    ASSERT(anon.is_equal_same_type(ex_to_lorentzidx(v2.seq[0]).create_anonymous_representative()));
+    return spmapkey(strstrpair(v1.name,v2.name),anon);
+}
+
+
+
diff --git a/ginac/simp_lor.h b/ginac/simp_lor.h
new file mode 100644 (file)
index 0000000..8efe1b3
--- /dev/null
@@ -0,0 +1,152 @@
+/** @file simp_lor.h
+ *
+ *  Interface to GiNaC's simp_lor objects. */
+
+#ifndef _SIMP_LOR_H_
+#define _SIMP_LOR_H_
+
+#include <string>
+#include <vector>
+#include <utility>
+#include <map>
+#include <iostream>
+
+class simp_lor;
+
+#include "indexed.h"
+#include "lorentzidx.h"
+
+typedef pair<string,string> strstrpair;
+typedef pair<strstrpair,lorentzidx> spmapkey;
+
+class spmapkey_is_less
+{
+public:
+    bool operator()(spmapkey const & lh, spmapkey const & rh) const
+    {
+        /*
+        cerr << "spmapkey_is_less" << endl;
+        cerr << "lh=((" << lh.first.first
+             << "," << lh.first.second << "),";
+        lh.second.printraw(cerr);
+        cerr << ")" << endl;
+
+        cerr << "rh=((" << rh.first.first
+             << "," << rh.first.second << "),";
+        rh.second.printraw(cerr);
+        cerr << ")" << endl;
+        */
+        bool res=lh.first<rh.first ||
+            (!(rh.first<lh.first) && lh.second.compare(rh.second)<0 );
+        // cout << "result=" << res << endl;
+        return res;
+    }
+};
+
+typedef map<spmapkey,ex,spmapkey_is_less> spmap;
+
+class simp_lor;
+
+/** helper class for scalar products */
+class scalar_products
+{
+public:
+    void reg(simp_lor const & v1, simp_lor const & v2, ex const & sp);
+    bool is_defined(simp_lor const & v1, simp_lor const & v2) const;
+    ex evaluate(simp_lor const & v1, simp_lor const & v2) const;
+    void debugprint(void) const;
+protected:
+    static spmapkey make_key(simp_lor const & v1, simp_lor const & v2);
+protected:
+    spmap spm;
+};
+
+/** Base class for simp_lor object */
+class simp_lor : public indexed
+{
+// friends
+
+    friend class scalar_products;
+    friend simp_lor lor_g(ex const & mu, ex const & nu);
+    friend simp_lor lor_vec(string const & n, ex const & mu);
+    friend ex simplify_simp_lor_mul(ex const & m, scalar_products const & sp);
+    friend ex simplify_simp_lor(ex const & e, scalar_products const & sp);
+    
+// types
+
+public:
+    typedef enum { invalid, // not properly constructed by one of the friend functions
+                   simp_lor_g,
+                   simp_lor_vec
+    } simp_lor_types;
+    
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    simp_lor();
+    ~simp_lor();
+    simp_lor(simp_lor const & other);
+    simp_lor const & operator=(simp_lor const & other);
+protected:
+    void copy(simp_lor const & other); 
+    void destroy(bool call_parent);
+
+    // other constructors
+protected:
+    simp_lor(simp_lor_types const t);
+    simp_lor(simp_lor_types const t, ex const & i1, ex const & i2);
+    simp_lor(simp_lor_types const t, string const & n, ex const & i1);
+    simp_lor(simp_lor_types const t, string const & n, exvector const & iv);
+    simp_lor(simp_lor_types const t, string const & n, exvector * ivp);
+    
+    // functions overriding virtual functions from base classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+    ex eval(int level=0) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    ex thisexprseq(exvector const & v) const;
+    ex thisexprseq(exvector * vp) const;
+
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+protected:
+    bool all_of_type_lorentzidx(void) const;
+    
+// member variables
+
+protected:
+    simp_lor_types type;
+    string name;
+};
+
+// global constants
+
+extern const simp_lor some_simp_lor;
+extern type_info const & typeid_simp_lor;
+
+// macros
+
+#define ex_to_simp_lor(X) static_cast<simp_lor const &>(*(X).bp)
+#define ex_to_nonconst_simp_lor(X) static_cast<simp_lor &>(*(X).bp)
+
+simp_lor lor_g(ex const & mu, ex const & nu);
+simp_lor lor_vec(string const & n, ex const & mu);
+ex simplify_simp_lor_mul(ex const & m, scalar_products const & sp);
+ex simplify_simp_lor(ex const & e, scalar_products const & sp);
+ex Dim(void);
+
+#endif // ndef _SIMP_LOR_H_
+
+
diff --git a/ginac/structure.cpp b/ginac/structure.cpp
new file mode 100644 (file)
index 0000000..d17bab2
--- /dev/null
@@ -0,0 +1,156 @@
+/** @file structure.cpp
+ *
+ *  Implementation of 'abstract' class structure. */
+
+#include <string>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+structure::structure()
+{
+    debugmsg("structure default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key = TINFO_STRUCTURE;
+}
+
+structure::~structure()
+{
+    debugmsg("structure destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+structure::structure(structure const & other)
+{
+    debugmsg("structure copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+structure const & structure::operator=(structure const & other)
+{
+    debugmsg("structure operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        copy(other);
+    }
+    return *this;
+}
+
+// protected
+
+void structure::copy(structure const & other)
+{
+    basic::copy(other);
+}
+
+void structure::destroy(bool call_parent)
+{
+    if (call_parent) basic::destroy(call_parent);
+}
+
+//////////
+// other constructors
+//////////
+
+// none
+
+//////////
+// structures overriding virtual structures from bases classes
+//////////
+
+// public
+
+basic * structure::duplicate() const
+{
+    debugmsg("structure duplicate",LOGLEVEL_DUPLICATE);
+    return new structure(*this);
+}
+
+void structure::printraw(ostream & os) const
+{
+    debugmsg("structure printraw",LOGLEVEL_PRINT);
+
+    os << "structure(hash=" << hashvalue << ",flags=" << flags << ")";
+}
+
+void structure::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("structure print",LOGLEVEL_PRINT);
+
+    os << "structure()";
+}
+
+void structure::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("structure printtree",LOGLEVEL_PRINT);
+
+    os << string(indent,' ') << "structure "
+       << "hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
+       << ", flags=" << flags << endl;
+}
+
+void structure::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
+{
+    debugmsg("structure print csrc",LOGLEVEL_PRINT);
+
+    os << "structure()";
+}
+
+// protected
+
+int structure::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other, structure));
+    return 0; // all structures are the same
+}
+
+bool structure::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other, structure));
+    return true; // all structures are the same
+}
+
+//////////
+// new virtual structures which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual structures in this class
+//////////
+
+// protected
+
+vector<registered_structure_info> & structure::registered_structures(void)
+{
+    static vector<registered_structure_info> * rs=new vector<registered_structure_info>;
+    return *rs;
+}
+
+// public
+
+unsigned structure::register_new(char const * nm)
+{
+    registered_structure_info rsi={nm};
+    registered_structures().push_back(rsi);
+    return registered_structures().size()-1;
+}
+
+//////////
+// static member variables
+//////////
+
+// none
+
+//////////
+// global constants
+//////////
+
+const structure some_structure;
+type_info const & typeid_structure=typeid(some_structure);
+
diff --git a/ginac/structure.h b/ginac/structure.h
new file mode 100644 (file)
index 0000000..b1c8bef
--- /dev/null
@@ -0,0 +1,70 @@
+/** @file structure.h
+ *
+ *  Interface to 'abstract' class structure. */
+
+#ifndef _STRUCTURE_H_
+#define _STRUCTURE_H_
+
+class structure;
+
+#include "basic.h"
+
+struct registered_structure_info {
+    char const * name;
+};
+
+/** 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
+{
+// member functions
+
+    // default constructor, destructor, copy constructor 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 constructors
+    // none
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const; 
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+    
+    // non-virtual functions in this class
+protected:
+    static vector<registered_structure_info> & registered_structures(void);
+public:
+    static unsigned register_new(char const * nm);
+
+// member variables
+// none
+
+};
+
+// global constants
+
+extern const structure some_structure;
+extern type_info const & typeid_structure;
+
+#endif // ndef _STRUCTURE_H_
+
diff --git a/ginac/structure.pl b/ginac/structure.pl
new file mode 100755 (executable)
index 0000000..725b03a
--- /dev/null
@@ -0,0 +1,483 @@
+#!/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('    ex const & ${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!
+ */
+
+// structure.pl input:
+${input_structure}
+
+#ifndef _${STRUCTURE_UC}_H_
+#define _${STRUCTURE_UC}_H_
+
+#include <ginac/ginac.h>
+
+class ${STRUCTURE} : public structure
+{
+// member functions
+
+    // default constructor, destructor, copy constructor 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 constructors
+public:
+    ${STRUCTURE}(${constructor_arglist});
+
+    // functions overriding virtual functions from bases classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printtree(ostream & os, unsigned indent) const;
+    int nops() const;
+    ex & let_op(int const i);
+    ex expand(unsigned options=0) const;
+    bool has(ex const & 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(symbol const & s) const;
+    ex subs(lst const & ls, lst const & lr) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & 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 type_info const & typeid_${STRUCTURE};
+extern const unsigned tinfo_${STRUCTURE};
+
+// macros
+
+#define ex_to_${STRUCTURE}(X) (static_cast<${STRUCTURE} const &>(*(X).bp))
+
+#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!
+ */
+
+// structure.pl input:
+${input_structure}
+
+#include <iostream>
+
+#include "ginac.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+
+${STRUCTURE}::${STRUCTURE}()
+{
+    debugmsg("${STRUCTURE} default constructor",LOGLEVEL_CONSTRUCT);
+    tinfo_key=tinfo_${STRUCTURE};
+}
+
+${STRUCTURE}::~${STRUCTURE}()
+{
+    debugmsg("${STRUCTURE} destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+${STRUCTURE}::${STRUCTURE}(${STRUCTURE} const & other)
+{
+    debugmsg("${STRUCTURE} copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+${STRUCTURE} const & ${STRUCTURE}::operator=(${STRUCTURE} const & other)
+{
+    debugmsg("${STRUCTURE} operator=",LOGLEVEL_ASSIGNMENT);
+    if (this != &other) {
+        destroy(1);
+        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 constructors
+//////////
+
+// public
+
+${STRUCTURE}::${STRUCTURE}(${constructor_arglist}) 
+    : ${constructor_statements}
+{
+    debugmsg("${STRUCTURE} constructor from children",
+             LOGLEVEL_CONSTRUCT);
+    tinfo_key=tinfo_${STRUCTURE};
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * ${STRUCTURE}::duplicate() const
+{
+    debugmsg("${STRUCTURE} duplicate",LOGLEVEL_DUPLICATE);
+    return new ${STRUCTURE}(*this);
+}
+
+void ${STRUCTURE}::printraw(ostream & os) const
+{
+    debugmsg("${STRUCTURE} printraw",LOGLEVEL_PRINT);
+    os << "${STRUCTURE}()";
+}
+
+void ${STRUCTURE}::print(ostream & os, unsigned upper_precedence) const
+{
+    debugmsg("${STRUCTURE} print",LOGLEVEL_PRINT);
+    os << "${STRUCTURE}()";
+}
+
+void ${STRUCTURE}::printtree(ostream & os, unsigned indent) const
+{
+    debugmsg("${STRUCTURE} printtree",LOGLEVEL_PRINT);
+    os << "${STRUCTURE}()";
+}
+
+int ${STRUCTURE}::nops() const
+{
+    return ${number_of_members};
+}
+
+ex & ${STRUCTURE}::let_op(int const i)
+{
+    ASSERT(i>=0);
+    ASSERT(i<nops());
+
+    switch (i) {
+${let_op_statements}
+    }
+    errormsg("${STRUCTURE}::let_op(): should not reach this point");
+    return *new ex(fail());
+}
+
+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(ex const & other) const
+{
+    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(symbol const & s) const
+{
+${diff_statements}
+    return ${STRUCTURE}(${temporary_arglist});
+}
+
+ex ${STRUCTURE}::subs(lst const & ls, lst const & 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(basic const & other) const
+{
+    ASSERT(is_of_type(other,${STRUCTURE}));
+    ${STRUCTURE} const & o=static_cast<${STRUCTURE} const &>
+                                    (const_cast<basic &>(other));
+    int cmpval;
+${compare_statements}
+    return 0;
+}
+
+bool ${STRUCTURE}::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,${STRUCTURE}));
+    ${STRUCTURE} const & o=static_cast<${STRUCTURE} const &>
+                                    (const_cast<basic &>(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};
+type_info const & typeid_${STRUCTURE}=typeid(some_${STRUCTURE});
+const unsigned tinfo_${STRUCTURE}=structure::register_new("${STRUCTURE}");
+
+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";
diff --git a/ginac/symbol.cpp b/ginac/symbol.cpp
new file mode 100644 (file)
index 0000000..6822dc4
--- /dev/null
@@ -0,0 +1,259 @@
+/** @file symbol.cpp
+ *
+ *  Implementation of GiNaC's symbolic objects. */
+
+#include <string>
+#include <stdexcept>
+
+#include "ginac.h"
+#include "utils.h"
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+symbol::symbol() : basic(TINFO_SYMBOL)
+{
+    debugmsg("symbol default constructor",LOGLEVEL_CONSTRUCT);
+    serial=next_serial++;
+    name=autoname_prefix()+ToString(serial);
+    asexinfop=new assigned_ex_info;
+    setflag(status_flags::evaluated);
+}
+
+symbol::~symbol()
+{
+    debugmsg("symbol destructor",LOGLEVEL_DESTRUCT);
+    destroy(0);
+}
+
+symbol::symbol(symbol const & other)
+{
+    debugmsg("symbol copy constructor",LOGLEVEL_CONSTRUCT);
+    copy(other);
+}
+
+void symbol::copy(symbol const & other)
+{
+    basic::copy(other);
+    name=other.name;
+    serial=other.serial;
+    asexinfop=other.asexinfop;
+    ++asexinfop->refcount;
+}
+
+void symbol::destroy(bool call_parent)
+{
+    if (--asexinfop->refcount == 0) {
+        delete asexinfop;
+    }
+    if (call_parent) {
+        basic::destroy(call_parent);
+    }
+}
+
+// how should the following be interpreted?
+// symbol x;
+// symbol y;
+// x=y;
+// probably as: x=ex(y);
+
+//////////
+// other constructors
+//////////
+
+// public
+
+symbol::symbol(string const & initname) : basic(TINFO_SYMBOL)
+{
+    debugmsg("symbol constructor from string",LOGLEVEL_CONSTRUCT);
+    name=initname;
+    serial=next_serial++;
+    asexinfop=new assigned_ex_info;
+    setflag(status_flags::evaluated);
+}
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+
+basic * symbol::duplicate() const
+{
+    debugmsg("symbol duplicate",LOGLEVEL_DUPLICATE);
+    return new symbol(*this);
+}
+
+bool symbol::info(unsigned inf) const
+{
+    if (inf==info_flags::symbol) return true;
+    if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
+        return true;
+    } else {
+        return basic::info(inf);
+    }
+}
+
+ex symbol::expand(unsigned options) const
+{
+    return this->hold();
+}
+
+bool symbol::has(ex const & other) const
+{
+    if (is_equal(*other.bp)) return true;
+    return false;
+}
+
+int symbol::degree(symbol const & s) const
+{
+    return compare_same_type(s)==0 ? 1 : 0;
+}
+
+int symbol::ldegree(symbol const & s) const
+{
+    return compare_same_type(s)==0 ? 1 : 0;
+}
+
+ex symbol::coeff(symbol const & s, int const n) const
+{
+    if (compare_same_type(s)==0) {
+        return n==1 ? exONE() : exZERO();
+    } else {
+        return n==0 ? *this : exZERO();
+    }
+}
+
+ex symbol::eval(int level) const
+{
+    if (level == -max_recursion_level) {
+        throw(std::runtime_error("max recursion level reached"));
+    }
+    
+    if (asexinfop->is_assigned) {
+        setflag(status_flags::evaluated);
+        if (level==1) {
+            return (asexinfop->assigned_expression);
+        } else {
+            return (asexinfop->assigned_expression).eval(level);
+        }
+    } else {
+        return this->hold();
+    }
+}
+
+ex symbol::subs(lst const & ls, lst const & lr) const
+{
+    ASSERT(ls.nops()==lr.nops());
+#ifdef DOASSERT
+    for (int i=0; i<ls.nops(); i++) {
+        ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
+               is_ex_of_type(ls.op(i),idx));
+    }
+#endif // def DOASSERT
+
+    for (int i=0; i<ls.nops(); i++) {
+        if (is_ex_exactly_of_type(ls.op(i),symbol)) {
+            if (compare_same_type(ex_to_symbol(ls.op(i)))==0) return lr.op(i);
+        }
+    }
+    return *this;
+}
+
+// protected
+
+int symbol::compare_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,symbol));
+    const symbol *o = static_cast<const symbol *>(&other);
+    if (serial==o->serial) return 0;
+    return serial < o->serial ? -1 : 1;
+}
+
+bool symbol::is_equal_same_type(basic const & other) const
+{
+    ASSERT(is_of_type(other,symbol));
+    const symbol *o = static_cast<const symbol *>(&other);
+    return serial==o->serial;
+}
+
+unsigned symbol::return_type(void) const
+{
+    return return_types::commutative;
+}
+   
+unsigned symbol::return_type_tinfo(void) const
+{
+    return tinfo_key;
+}
+
+unsigned symbol::calchash(void) const
+{
+    // return golden_ratio_hash(tinfo()) ^ serial;
+    hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555555U ^ serial));
+    setflag(status_flags::hash_calculated);
+    return hashvalue;
+}
+
+//////////
+// virtual functions which can be overridden by derived classes
+//////////
+
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+
+void symbol::assign(ex const & value)
+{
+    asexinfop->is_assigned=1;
+    asexinfop->assigned_expression=value;
+    clearflag(status_flags::evaluated);
+}
+
+void symbol::unassign(void)
+{
+    if (asexinfop->is_assigned) {
+        asexinfop->is_assigned=0;
+        asexinfop->assigned_expression=exZERO();
+    }
+    setflag(status_flags::evaluated);
+}
+
+// private
+
+string & symbol::autoname_prefix(void)
+{
+    static string * s=new string("symbol");
+    return *s;
+}
+
+//////////
+// static member variables
+//////////
+
+// private
+
+unsigned symbol::next_serial=0;
+
+// string const symbol::autoname_prefix="symbol";
+
+//////////
+// global constants
+//////////
+
+const symbol some_symbol;
+type_info const & typeid_symbol=typeid(some_symbol);
+
+//////////
+// subclass assigned_ex_info
+//////////
+
+/** Default ctor.  Defaults to unassigned. */
+symbol::assigned_ex_info::assigned_ex_info(void) : is_assigned(0), refcount(1)
+{
+}
diff --git a/ginac/symbol.h b/ginac/symbol.h
new file mode 100644 (file)
index 0000000..a10998e
--- /dev/null
@@ -0,0 +1,111 @@
+/** @file symbol.h
+ *
+ *  Interface to GiNaC's symbolic objects. */
+
+#ifndef _SYMBOL_H_
+#define _SYMBOL_H_
+
+#include <string>
+
+class symbol;
+
+#include "basic.h"
+#include "ex.h"
+
+/** Basic CAS symbol.  It has a name because it must know how to output itself.
+ *  It may be assigned an expression, but this feature is only intended for
+ *  programs like 'ginsh' that want to associate symbols with expressions.
+ *  If you want to replace symbols by expressions in your code, you should
+ *  use ex::subs() or use objects of class ex instead of class symbol in the
+ *  first place. */
+class symbol : public basic
+{
+// types
+    /** Symbols as keys to expressions. */
+    class 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;      //!< Yet another refcounter. PLEASE EXPLAIN!
+    };
+    
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+public:
+    symbol();
+    ~symbol();
+    symbol(symbol const & other);
+protected:
+    void copy(symbol const & other); 
+    void destroy(bool call_parent);
+
+    // other constructors
+public:
+    explicit symbol(string const & initname);
+
+    // functions overriding virtual functions from base classes
+public:
+    basic * duplicate() const;
+    void printraw(ostream & os) const;
+    void printtree(ostream & os, unsigned indent) const;
+    void print(ostream & os, unsigned upper_precedence=0) const;
+    void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
+    bool info(unsigned inf) const;
+    ex expand(unsigned options=0) const;
+    bool has(ex const & other) const;
+    int degree(symbol const & s) const;
+    int ldegree(symbol const & s) const;
+    ex coeff(symbol const & s, int const n = 1) const;
+    ex eval(int level = 0) const;
+    ex diff(symbol const & s) const;
+    ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
+    ex subs(lst const & ls, lst const & lr) const;
+protected:
+    int compare_same_type(basic const & other) const;
+    bool is_equal_same_type(basic const & other) const;
+    unsigned return_type(void) const;
+    unsigned return_type_tinfo(void) const;
+    unsigned calchash(void) const;
+    
+    // non-virtual functions in this class
+public:
+    void assign(ex const & value);
+    void unassign(void);
+    ex diff(symbol const & s, unsigned nth) const;
+    void setname(string const & n) {name=n;}
+    string getname(void) const {return name;}
+private:
+    string & autoname_prefix(void);
+
+// member variables
+
+protected:
+    assigned_ex_info * asexinfop;
+    unsigned serial;  //!< unique serial number for comparision
+    string name;
+private:
+    static unsigned next_serial;
+};
+
+// global constants
+
+extern const symbol some_symbol;
+extern type_info const & typeid_symbol;
+
+// macros
+
+#define ex_to_symbol(X) static_cast<symbol const &>(*(X).bp)
+
+// wrapper functions around member functions
+inline void unassign(symbol & symarg)
+{ return symarg.unassign(); }
+
+inline int degree(symbol const & a, symbol const & s)
+{ return a.degree(s); }
+
+inline int ldegree(symbol const & a, symbol const & s)
+{ return a.ldegree(s); }
+
+#endif // ndef _SYMBOL_H_
diff --git a/ginac/tinfos.h b/ginac/tinfos.h
new file mode 100644 (file)
index 0000000..de799aa
--- /dev/null
@@ -0,0 +1,51 @@
+/** @file tinfos.h
+ *
+ *  Values for a do-it-yourself typeinfo scheme. */
+
+#ifndef _TINFOS_H_
+#define _TINFOS_H_
+
+#define TINFO_BASIC        0x00000001U
+
+#define TINFO_EXPAIRSEQ    0x00010001U
+#define TINFO_ADD          0x00011001U
+#define TINFO_MUL          0x00011002U
+
+#define TINFO_SYMBOL       0x00020001U
+#define TINFO_CONSTANT     0x00021001U
+
+#define TINFO_EXPRSEQ      0x00030001U
+#define TINFO_FUNCTION     0x00031001U
+#define TINFO_NCMUL        0x00031002U
+// #define TINFO_NFUNCTION     0x00031003U
+
+#define TINFO_LST          0x00040001U
+
+#define TINFO_MATRIX       0x00050001U
+
+#define TINFO_POWER        0x00060001U
+
+#define TINFO_RELATIONAL   0x00070001U
+
+#define TINFO_FAIL         0x00080001U
+
+#define TINFO_NUMERIC      0x00090001U
+
+#define TINFO_SERIES       0x000a0001U
+
+#define TINFO_INDEXED      0x000b0001U
+#define TINFO_ALGEBRA      0x000b1001U
+#define TINFO_CLIFFORD     0x000b1101U
+#define TINFO_COLOR        0x000b1201U
+#define TINFO_ISOSPIN      0x000b1301U
+#define TINFO_SIMP_LOR     0x000b1401U
+
+#define TINFO_STRUCTURE    0x000c0001U
+// reserved up to          0x000cffffU
+// for user defined structures
+
+#define TINFO_IDX          0x000d0001U
+#define TINFO_COLORIDX     0x000d1001U
+#define TINFO_LORENTZIDX   0x000d1002U
+
+#endif // ndef _TINFOS_H_
diff --git a/ginac/utils.cpp b/ginac/utils.cpp
new file mode 100644 (file)
index 0000000..ae0160d
--- /dev/null
@@ -0,0 +1,98 @@
+/** @file utils.cpp
+ *
+ *  Implementation of several small and furry utilities. */
+
+unsigned log2(unsigned n)
+{
+    unsigned k;
+    for (k = 0; n > 1; n >>= 1) ++k;
+    return k;
+}
+
+int compare_pointers(void const * a, void const * b)
+{
+    if (a<b) {
+        return -1;
+    } else if (a>b) {
+        return 1;
+    }
+    return 0;
+}
+
+// comment skeletton for header files
+
+
+// member functions
+
+    // default constructor, destructor, copy constructor assignment operator and helpers
+    // none
+
+    // other constructors
+    // none
+
+    // functions overriding virtual functions from bases classes
+    // none
+    
+    // new virtual functions which can be overridden by derived classes
+    // none
+
+    // non-virtual functions in this class
+    // none
+
+// member variables
+// none
+    
+
+
+// comment skeletton for implementation files
+
+
+//////////
+// default constructor, destructor, copy constructor assignment operator and helpers
+//////////
+
+// public
+// protected
+
+//////////
+// other constructors
+//////////
+
+// public
+// none
+
+//////////
+// functions overriding virtual functions from bases classes
+//////////
+
+// public
+// protected
+// none
+
+//////////
+// new virtual functions which can be overridden by derived classes
+//////////
+
+// public
+// protected
+// none
+
+//////////
+// non-virtual functions in this class
+//////////
+
+// public
+// protected
+// none
+
+//////////
+// static member variables
+//////////
+
+// protected
+// private
+// none
+
+
+
+
diff --git a/ginac/utils.h b/ginac/utils.h
new file mode 100644 (file)
index 0000000..a19aea4
--- /dev/null
@@ -0,0 +1,75 @@
+/** @file utils.h
+ *
+ *  Interface to several small and furry utilities. */
+
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include <strstream>
+#include <string>
+#include "config.h"
+
+template<class T>
+string ToString(T const & t)
+{
+    char buf[256];
+    ostrstream(buf,sizeof(buf)) << t << ends;
+    return buf;
+}
+
+unsigned log2(unsigned n);
+
+int compare_pointers(void const * a, void const * b);
+
+#define DYNCONSTCAST(FINALTYPE,BASICTYPE,EXPRESSION) \
+    dynamic_cast<FINALTYPE>(const_cast<BASICTYPE>(EXPRESSION))
+
+// modified from stl_algo.h: always do com(*first1,*first2) instead of comp(*first2,*first1)
+template <class InputIterator1, class InputIterator2, class OutputIterator,
+          class Compare>
+OutputIterator mymerge(InputIterator1 first1, InputIterator1 last1,
+                       InputIterator2 first2, InputIterator2 last2,
+                       OutputIterator result, Compare comp) {
+  while (first1 != last1 && first2 != last2) {
+    if (comp(*first1, *first2)) {
+      *result = *first1;
+      ++first1;
+    }
+    else {
+      *result = *first2;
+      ++first2;
+    }
+    ++result;
+  }
+  return copy(first2, last2, copy(first1, last1, result));
+}
+
+// like merge(), but three lists with *last2<*first3
+template <class InputIterator1, class InputIterator2, class InputIterator3,
+          class OutputIterator, class Compare>
+OutputIterator mymerge3(InputIterator1 first1, InputIterator1 last1,
+                        InputIterator2 first2, InputIterator2 last2,
+                        InputIterator3 first3, InputIterator3 last3,
+                        OutputIterator result, Compare comp) {
+  while (first1 != last1 && first2 != last2) {
+    if (comp(*first1, *first2)) {
+      *result = *first1;
+      ++first1;
+    }
+    else {
+      *result = *first2;
+      ++first2;
+    }
+    ++result;
+  }
+
+  if (first1==last1) {
+    // list1 empty, copy rest of list2, then list3
+    return copy(first3, last3, copy(first2, last2, result));
+  } else {
+    // list2 empty, merge rest of list1 with list3
+    return mymerge(first1,last1,first3,last3,result,comp);
+  }
+}
+
+#endif // ndef _UTILS_H_
diff --git a/ginsh/Makefile.am b/ginsh/Makefile.am
new file mode 100644 (file)
index 0000000..25a5d8e
--- /dev/null
@@ -0,0 +1,6 @@
+## Process this file with automake to produce Makefile.in
+bin_PROGRAMS = ginsh
+ginsh_SOURCES = ginsh_parser.yy ginsh_lexer.ll ginsh.h
+ginsh_LDADD = @LIBOBJS@ ../ginac/libginac.la
+man_MANS = ginsh.1
+YFLAGS = -d
index fefd5d5ab487d434e3e6df5710496fb4f5cde8c7..1ed7443735134207109ffe83e56efa7ed6f3620e 100644 (file)
-# This is the prototype Makefile for the GiNaC interactive shell (ginsh).
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
 
-# Not every make knows what CXX is, so we inherit it together with some other
-# values from configure which checks it anyways:
-CXX = @CXX@
-CXXFLAGS = @CXXFLAGS@
-CPPFLAGS = @CPPFLAGS@ -I.. -I../include
-DEFS = @DEFS@
-LIBS = @LIBS@ @LEXLIB@
-LDFLAGS = @LDFLAGS@
-LEX = @LEX@
-YACC = @YACC@
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
 
-# Here come the usual install directories in GNU-configure fashion:
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
 prefix = @prefix@
 exec_prefix = @exec_prefix@
+
 bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
 mandir = @mandir@
-man1dir = ${mandir}/man1
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
 
-# This must be empty if configure couldn't find it in ${PATH}:
-MAKEDEPEND = @MAKEDEPEND@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
 
-# Autoconf macro AC_PROC_INSTALL sets these:
 INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@ -s
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CC = @CC@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+DOXYGEN = @DOXYGEN@
+DVIPS = @DVIPS@
+FIG2DEV = @FIG2DEV@
+JADE = @JADE@
+JADETEX = @JADETEX@
+LATEX = @LATEX@
+LD = @LD@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINDEX = @MAKEINDEX@
+MAKEINFO = @MAKEINFO@
+NM = @NM@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+
+bin_PROGRAMS = ginsh
+ginsh_SOURCES = ginsh_parser.yy ginsh_lexer.ll ginsh.h
+ginsh_LDADD = @LIBOBJS@ ../ginac/libginac.la
+man_MANS = ginsh.1
+YFLAGS = -d
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+ginsh_OBJECTS =  ginsh_parser.o ginsh_lexer.o
+ginsh_DEPENDENCIES =  @LIBOBJS@ ../ginac/libginac.la
+ginsh_LDFLAGS = 
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LEXLIB = @LEXLIB@
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+CXXLINK = $(LIBTOOL) --mode=link $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
+man1dir = $(mandir)/man1
+MANS = $(man_MANS)
+
+NROFF = nroff
+DIST_COMMON =  Makefile.am Makefile.in ginsh_lexer.cc ginsh_parser.cc \
+strdup.c
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+DEP_FILES =  .deps/ginsh_lexer.P .deps/ginsh_parser.P .deps/strdup.P
+CXXMKDEP = $(CXX) -M $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS)
+SOURCES = $(ginsh_SOURCES)
+OBJECTS = $(ginsh_OBJECTS)
+
+all: Makefile $(PROGRAMS) $(MANS)
+
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .ll .lo .o .s .yy
+$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu ginsh/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+       -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(bindir)
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo " $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+           $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+         else :; fi; \
+       done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       list='$(bin_PROGRAMS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+       done
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
 
-OBJECTS=y.tab.o @LEX_OUTPUT_ROOT@.o
+maintainer-clean-compile:
 
-all:   
-       echo "Please call it with 'make ginsh' from top-level Makefile."
-       echo "Alternatively, you can use this Makefile's targets {shared|static}ginsh"
-       echo "depending on your personal preferences and which library you built."
+.s.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
 
-sharedginsh: depend ${OBJECTS}
-       ${CXX} ${CXXFLAGS} ${LDFLAGS} ${OBJECTS} ${LIBS} -Wl,--rpath -Wl,../src/.libs -L../src/.libs -lginac -o ginsh
+.S.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
 
-staticginsh: depend ${OBJECTS}
-       ${CXX} ${CXXFLAGS} ${LDFLAGS} ${OBJECTS} ${LIBS} ../src/.libs/libginac.a -o ginsh
+mostlyclean-libtool:
+       -rm -f *.lo
 
-# Targets for installation in install directories.
-install: ginsh installdirs
-       ${INSTALL_PROGRAM} ginsh ${bindir}/ginsh
-       -${INSTALL_DATA} ginsh.1 ${man1dir}/ginsh.1
+clean-libtool:
+       -rm -rf .libs _libs
 
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+ginsh: $(ginsh_OBJECTS) $(ginsh_DEPENDENCIES)
+       @rm -f ginsh
+       $(CXXLINK) $(ginsh_LDFLAGS) $(ginsh_OBJECTS) $(ginsh_LDADD) $(LIBS)
+.yy.cc:
+       $(YACC) $(YFLAGS) $< && mv y.tab.c $*.cc
+       if test -f y.tab.h; then \
+       if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
+       else :; fi
+ginsh_parser.hh: ginsh_parser.cc
+
+.ll.cc:
+       $(LEX) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@
+.cc.o:
+       $(CXXCOMPILE) -c $<
+.cc.lo:
+       $(LTCXXCOMPILE) -c $<
+
+install-man1:
+       $(mkinstalldirs) $(DESTDIR)$(man1dir)
+       @list='$(man1_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.1*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+         else file=$$i; fi; \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
+         $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
+       done
+
+uninstall-man1:
+       @list='$(man1_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.1*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
+         rm -f $(DESTDIR)$(man1dir)/$$inst; \
+       done
+install-man: $(MANS)
+       @$(NORMAL_INSTALL)
+       $(MAKE) install-man1
+uninstall-man:
+       @$(NORMAL_UNINSTALL)
+       $(MAKE) uninstall-man1
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = ginsh
+
+distdir: $(DISTFILES)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(top_distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu ginsh/Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+
+maintainer-clean-depend:
+       -rm -rf .deps
+
+%.o: %.c
+       @echo '$(COMPILE) -c $<'; \
+       $(COMPILE) -Wp,-MD,.deps/$(*F).P -c $<
+
+%.lo: %.c
+       @echo '$(LTCOMPILE) -c $<'; \
+       $(LTCOMPILE) -Wp,-MD,.deps/$(*F).p -c $<
+       @-sed -e 's/^\([^:]*\)\.o:/\1.lo \1.o:/' \
+         < .deps/$(*F).p > .deps/$(*F).P
+       @-rm -f .deps/$(*F).p
+
+%.o: %.cc
+       @echo '$(CXXCOMPILE) -c $<'; \
+       $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).P -c $<
+
+%.lo: %.cc
+       @echo '$(LTCXXCOMPILE) -c $<'; \
+       $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).p -c $<
+       @-sed -e 's/^\([^:]*\)\.o:/\1.lo \1.o:/' \
+         < .deps/$(*F).p > .deps/$(*F).P
+       @-rm -f .deps/$(*F).p
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: install-binPROGRAMS
+       @$(NORMAL_INSTALL)
+
+install-data: install-man
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: uninstall-binPROGRAMS uninstall-man
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
 installdirs:
-       ../mkinstalldirs ${bindir} ${man1dir}
-
-# Targets for cleaning up. (clean deletes files created by built, distclean
-# deletes files created by configuration, uninstall removes all files related
-# to ginsh from the system.)
-clean:
-       rm -f y.tab.c y.tab.h @LEX_OUTPUT_ROOT@.c
-       rm -f *.o *.lo core ginsh
-
-distclean: clean
-       rm -f config.status config.log config.cache config.h Makefile Makefile.bak
-
-uninstall:
-       rm -f ${bindir}/ginsh
-       rm -f ${man1dir}/ginsh.1
-
-# If Todd Brunhoff's makedepend is installed (it may not---it's part of X11);
-# then call it; else wait for trouble ahead; fi;    # :-)
-depend:
-       @if [ ${MAKEDEPEND} ]; then \
-               echo "calling ${MAKEDEPEND}"; \
-               ${MAKEDEPEND} -Y. -Y../include *.cpp 2> /dev/null; \
-       fi
-
-# Special dummy targets:
-.PHONY: clean distclean depend all install uninstall check doc
-.SUFFIXES: .o .c .h .y .l
-.SILENT: all
-
-# Suffix rules:
-.c.o :
-       ${CXX} ${CPPFLAGS} ${CXXFLAGS} ${DEFS} -c $<
-
-# Explicit rules:
-y.tab.c y.tab.h: ginsh.y
-       $(YACC) -d ginsh.y
-
-@LEX_OUTPUT_ROOT@.c: ginsh.l
-       $(LEX) ginsh.l
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
+       $(mkinstalldirs)  $(DATADIR)$(bindir) $(DESTDIR)$(mandir)/man1
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-binPROGRAMS mostlyclean-compile \
+               mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+               mostlyclean-generic
+
+clean:  clean-binPROGRAMS clean-compile clean-libtool clean-tags \
+               clean-depend clean-generic mostlyclean
+
+distclean:  distclean-binPROGRAMS distclean-compile distclean-libtool \
+               distclean-tags distclean-depend distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-binPROGRAMS maintainer-clean-compile \
+               maintainer-clean-libtool maintainer-clean-tags \
+               maintainer-clean-depend maintainer-clean-generic \
+               distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool install-man1 uninstall-man1 \
+install-man uninstall-man tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir mostlyclean-depend \
+distclean-depend clean-depend maintainer-clean-depend info dvi \
+installcheck install-exec install-data install uninstall all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
index 24f37c00555990eec0934280bf5935b123338f33..335e0f1af91613ecb60102879b584d6c284637a8 100644 (file)
@@ -2,8 +2,8 @@
  *  ginsh.h - GiNaC Interactive Shell, global definitions
  */
 
-#ifndef GINSH_H_
-#define GINSH_H_
+#ifndef GINSH_H
+#define GINSH_H
 
 // yacc semantic type
 #define YYSTYPE ex
@@ -21,14 +21,9 @@ extern char yytext[];
 typedef map<string, symbol> sym_tab;
 extern sym_tab syms;
 
-// Ersatz functions
+// Prototypes for missing functions
 #ifndef HAVE_STRDUP
-char *strdup(const char *s)
-{
-       char *n = (char *)malloc(strlen(s) + 1);
-       strcpy(n, s);
-       return n;
-}
+extern char *strdup(const char *s);
 #endif
 
 #endif
similarity index 96%
rename from ginsh/ginsh.l
rename to ginsh/ginsh_lexer.ll
index 6f4fb212a92806e36adfdf1f2ab6145763f05dc3..b282f836ab0a7c93615e7000a0771f06c1bdad71 100644 (file)
 %{
 #include "config.h"
 
-#if STDC_HEADERS
 #include <stdio.h>
-#endif
-
 extern "C" {
 #include <readline/readline.h>
 #include <readline/history.h>
 }
 #include <map>
 
-#include <GiNaC/ginac.h>
-
+#include <ginac/ginac.h>
 #include "ginsh.h"
-#include "y.tab.h"
+
+#include "ginsh_parser.h"
 
 #define YY_INPUT(buf, result, max_size) (result = ginsh_input(buf, max_size))
 
@@ -157,3 +154,9 @@ static int ginsh_input(char *buf, int max_size)
 
        return result;
 }
+
+// Scanner terminates on EOF
+int yywrap()
+{
+       return 1;
+}
similarity index 99%
rename from ginsh/ginsh.y
rename to ginsh/ginsh_parser.yy
index e0d1de843e66d934b3d83e4455b5a38d8f8b895f..6601a2a04e2c950fdcea3c733ef6aed37f1feb74 100644 (file)
 #include <unistd.h>
 #endif
 
-#if STDC_HEADERS
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#endif
 
 extern "C" {
 #include <readline/readline.h>
 #include <readline/history.h>
 }
+
 #include <map>
 #include <string>
 #include <stdexcept>
 
-#include <GiNaC/ginac.h>
-
+#include <ginac/ginac.h>
 #include "ginsh.h"
 
 // Original readline settings
diff --git a/ginsh/strdup.c b/ginsh/strdup.c
new file mode 100644 (file)
index 0000000..267186d
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ *  Replacement for strdup() function
+ */
+
+char *strdup(const char *s)
+{
+       char *n = (char *)malloc(strlen(s) + 1);
+       strcpy(n, s);
+       return n;
+}
diff --git a/ltconfig b/ltconfig
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/ltmain.sh b/ltmain.sh
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644 (file)
index 0000000..e69de29