--- /dev/null
+## Process this file with automake to produce Makefile.in
+SUBDIRS = ginac check ginsh doc
-# 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:
--- /dev/null
+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
+])
+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.
;;
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])
+
--- /dev/null
+## 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
-# 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:
// 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());
unsigned lsolve_onedim();
unsigned series_expansion();
-#endif // ndef _CHECK_H_
+#endif // ndef CHECK_H
/* 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)
* 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
/* 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)
/* 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)
{
// check/main.cpp
#include <stdexcept>
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
#include "check.h"
int main()
}
} catch (exception const & e) {
cout << "error: caught an exception: " << e.what() << endl;
+ result++;
}
if (result) {
/* Here we test manipulations on GiNaC's symbolic matrices. */
#include <stdexcept>
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
static unsigned matrix_determinants(void)
{
/* Rational function normalization test-suite. */
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
static symbol x("x"), y("y"), z("z");
* 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. */
// check/numeric_output.cpp
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
unsigned numeric_output(void)
{
* 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
/* 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;
/* 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)
{
--- /dev/null
+#! /bin/sh
+echo "Running checks..."
+./check_ginac 2>result.out
+echo "Comparing output..."
+cmp result.ref result.out
/* Series expansion test (Laurent and Taylor series). */
-#include <GiNaC/ginac.h>
+#include <ginac/ginac.h>
static symbol x("x");
/* 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
#! /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
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
# 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
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-*)
# 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
# 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
-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"
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
# 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
{ 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
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
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
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
# 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
# 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"
*) 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
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();
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
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"
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"
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. */
; 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
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"
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
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
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
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
/*)
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"
# 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
/*)
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"
# 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
/*)
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"
# 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
/*)
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"
# 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
/*)
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"
# 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
/*)
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"
# 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
/*)
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"
fi
-
-
-
trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure
# 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 \).
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 ;;
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
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
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
s%@FIG2DEV@%$FIG2DEV%g
s%@JADE@%$JADE%g
s%@JADETEX@%$JADETEX%g
-s%@shared@%$shared%g
-s%@LibGiNaC_Ver@%$LibGiNaC_Ver%g
CEOF
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
EOF
cat >> $CONFIG_STATUS <<EOF
+
EOF
cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
exit 0
EOF
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\"."
-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:
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\"."
+++ /dev/null
-# 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
--- /dev/null
+## Process this file with automake to produce Makefile.in
-# 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:
--- /dev/null
+## 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
--- /dev/null
+# 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:
--- /dev/null
+/** @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);
+
+
+
--- /dev/null
+/** @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_
+
--- /dev/null
+/** @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;
--- /dev/null
+/** @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_
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
+
--- /dev/null
+/** @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);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/** @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_
+
+
--- /dev/null
+/** @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);
+
+
+
--- /dev/null
+/** @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_
--- /dev/null
+/** @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);
--- /dev/null
+/** @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_
--- /dev/null
+#!/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";
--- /dev/null
+/** @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_
+
--- /dev/null
+/** @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;
+}
--- /dev/null
+/** @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;
+}
+
--- /dev/null
+/** @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_
--- /dev/null
+/** @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);
+ }
+};
+
+
+
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
+
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
--- /dev/null
+/** @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];
+}
+
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
+
--- /dev/null
+/** @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_
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
--- /dev/null
+#!/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";
--- /dev/null
+/* 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__ */
--- /dev/null
+/** @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;
+}
+
+
+
+
--- /dev/null
+/** @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_
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
+
--- /dev/null
+/** @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);
+}
+
--- /dev/null
+/** @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_
--- /dev/null
+/** @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);
--- /dev/null
+/** @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);
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
+
--- /dev/null
+/** @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);
+
+
+
--- /dev/null
+/** @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_
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
--- /dev/null
+/** @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);
+}
+
+
--- /dev/null
+/** @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);
--- /dev/null
+/** @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_
--- /dev/null
+/** @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);
+
+
--- /dev/null
+/** @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_
+
--- /dev/null
+/** @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);
+}
+
+
--- /dev/null
+/** @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_
+
--- /dev/null
+/** @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;
+}
--- /dev/null
+/** @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
--- /dev/null
+/** @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;
--- /dev/null
+/** @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_
--- /dev/null
+/** @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"));
+}
+
--- /dev/null
+/** @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_
+
--- /dev/null
+/** @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);
--- /dev/null
+/** @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_
+
--- /dev/null
+/** @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] << "]] ]]";
+}
--- /dev/null
+/** @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 << ")";
+}
--- /dev/null
+/** @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] << "))";
+}
--- /dev/null
+/** @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
+}
+
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
+
--- /dev/null
+/** @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);
--- /dev/null
+/** @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
--- /dev/null
+/** @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);
+}
+
+
+
--- /dev/null
+/** @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_
+
+
--- /dev/null
+/** @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);
+
--- /dev/null
+/** @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_
+
--- /dev/null
+#!/usr/bin/perl -w
+
+$input_structure='';
+$original_input_structure='';
+while (<>) {
+ $input_structure .= '// '.$_;
+ $original_input_structure .= $_;
+}
+
+$original_input_structure =~ tr/ \t\n\r\f/ /;
+$original_input_structure =~ tr/ //s;
+
+if ($original_input_structure =~ /^struct (\w+) ?\{ ?(.*)\}\;? ?$/) {
+ $STRUCTURE=$1;
+ $decl=$2;
+} else {
+ die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $original_input_structure";
+}
+
+# split off a part 'type var[,var...];' with a possible C-comment '/* ... */'
+while ($decl =~ /^ ?(\w+) ([\w \,]+)\; ?((\/\*.*?\*\/)?)(.*)$/) {
+ $type=$1;
+ $member=$2;
+ $comment=$3;
+ $decl=$5;
+ while ($member =~ /^(\w+) ?\, ?(.*)$/) {
+ push @TYPES,$type;
+ push @MEMBERS,$1;
+ push @COMMENTS,$comment;
+ if ($comment ne '') {
+ $comment='/* see above */';
+ }
+ $member=$2;
+ }
+ if ($member !~ /^\w$/) {
+ die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $input_structure";
+ }
+ push @TYPES,$type;
+ push @MEMBERS,$member;
+ push @COMMENTS,$comment;
+}
+
+if ($decl !~ /^ ?$/) {
+ die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $input_structure";
+}
+
+#$STRUCTURE='teststruct';
+$STRUCTURE_UC=uc(${STRUCTURE});
+#@TYPES=('ex','ex','ex');
+#@MEMBERS=('q10','q20','q21');
+
+sub generate {
+ my ($template,$conj)=@_;
+ my ($res,$N);
+
+ $res='';
+ for ($N=1; $N<=$#MEMBERS+1; $N++) {
+ $TYPE=$TYPES[$N-1];
+ $MEMBER=$MEMBERS[$N-1];
+ $COMMENT=$COMMENTS[$N-1];
+ $res .= eval('"' . $template . '"');
+ $TYPE=''; # to avoid main::TYPE used only once warning
+ $MEMBER=''; # same as above
+ $COMMENT=''; # same as above
+ if ($N!=$#MEMBERS+1) {
+ $res .= $conj;
+ }
+ }
+ return $res;
+}
+
+$number_of_members=$#MEMBERS+1;
+$constructor_arglist=generate('ex tmp_${MEMBER}',', ');
+$member_access_functions=generate(' 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";
--- /dev/null
+/** @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)
+{
+}
--- /dev/null
+/** @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_
--- /dev/null
+/** @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_
--- /dev/null
+/** @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
+
+
+
+
--- /dev/null
+/** @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_
--- /dev/null
+## 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
-# 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:
* 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
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
%{
#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))
return result;
}
+
+// Scanner terminates on EOF
+int yywrap()
+{
+ return 1;
+}
#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
--- /dev/null
+/*
+ * Replacement for strdup() function
+ */
+
+char *strdup(const char *s)
+{
+ char *n = (char *)malloc(strlen(s) + 1);
+ strcpy(n, s);
+ return n;
+}