From 6b3768e8c544739ae53321539cb4d1e3112ded1b Mon Sep 17 00:00:00 2001 From: Christian Bauer Date: Tue, 9 Nov 1999 22:56:40 +0000 Subject: [PATCH] - switched to automake build environment --- AUTHORS | 0 ChangeLog | 0 Makefile.am | 2 + Makefile.in | 445 +++++-- NEWS | 0 README | 0 acinclude.m4 | 116 ++ aclocal.m4 | 407 ++++++ check/Makefile.am | 8 + check/Makefile.in | 402 +++++- check/check.h | 6 +- check/differentiation.cpp | 2 +- check/expand_subs.cpp | 2 +- check/inifcns_consist.cpp | 2 +- check/lsolve_onedim.cpp | 2 +- check/main.cpp | 3 +- check/matrix_checks.cpp | 2 +- check/normalization.cpp | 2 +- check/numeric_consist.cpp | 2 +- check/numeric_output.cpp | 2 +- check/paranoia_check.cpp | 2 +- check/poly_gcd.cpp | 2 +- check/powerlaws.cpp | 2 +- check/run_checks | 5 + check/series_expansion.cpp | 2 +- config.guess | 0 config.h.in | 9 +- config.sub | 0 configure | 1860 ++++++++++++++++++---------- configure.in | 87 +- doc/Makefile | 169 --- doc/Makefile.am | 1 + doc/Makefile.in | 332 ++--- ginac/Makefile.am | 16 + ginac/Makefile.in | 383 ++++++ ginac/add.cpp | 635 ++++++++++ ginac/add.h | 94 ++ ginac/basic.cpp | 391 ++++++ ginac/basic.h | 240 ++++ ginac/clifford.cpp | 190 +++ ginac/clifford.h | 75 ++ ginac/color.cpp | 953 ++++++++++++++ ginac/color.h | 143 +++ ginac/coloridx.cpp | 196 +++ ginac/coloridx.h | 63 + ginac/constant.cpp | 143 +++ ginac/constant.h | 77 ++ ginac/container.pl | 816 ++++++++++++ ginac/debugmsg.h | 42 + ginac/diff.cpp | 208 ++++ ginac/ex.cpp | 490 ++++++++ ginac/ex.h | 269 ++++ ginac/expair.h | 173 +++ ginac/expairseq.cpp | 1604 ++++++++++++++++++++++++ ginac/expairseq.h | 183 +++ ginac/exprseq.cpp | 594 +++++++++ ginac/exprseq.h | 115 ++ ginac/exprseq_suppl.cpp | 21 + ginac/fail.cpp | 104 ++ ginac/fail.h | 58 + ginac/flags.h | 97 ++ ginac/function.cpp | 590 +++++++++ ginac/function.h | 276 +++++ ginac/function.pl | 613 +++++++++ ginac/ginac.h | 36 + ginac/idx.cpp | 427 +++++++ ginac/idx.h | 90 ++ ginac/indexed.cpp | 271 ++++ ginac/indexed.h | 81 ++ ginac/inifcns.cpp | 218 ++++ ginac/inifcns.h | 83 ++ ginac/inifcns_gamma.cpp | 80 ++ ginac/inifcns_trans.cpp | 717 +++++++++++ ginac/isospin.cpp | 190 +++ ginac/isospin.h | 75 ++ ginac/lorentzidx.cpp | 234 ++++ ginac/lorentzidx.h | 71 ++ ginac/lst.cpp | 611 +++++++++ ginac/lst.h | 116 ++ ginac/lst_suppl.cpp | 14 + ginac/matrix.cpp | 852 +++++++++++++ ginac/matrix.h | 133 ++ ginac/mul.cpp | 994 +++++++++++++++ ginac/mul.h | 103 ++ ginac/ncmul.cpp | 570 +++++++++ ginac/ncmul.h | 96 ++ ginac/normal.cpp | 1452 ++++++++++++++++++++++ ginac/normal.h | 35 + ginac/numeric.cpp | 1341 ++++++++++++++++++++ ginac/numeric.h | 307 +++++ ginac/operators.cpp | 382 ++++++ ginac/operators.h | 110 ++ ginac/power.cpp | 695 +++++++++++ ginac/power.h | 103 ++ ginac/print.cpp | 287 +++++ ginac/printcsrc.cpp | 297 +++++ ginac/printraw.cpp | 190 +++ ginac/printtree.cpp | 149 +++ ginac/relational.cpp | 244 ++++ ginac/relational.h | 85 ++ ginac/series.cpp | 610 +++++++++ ginac/series.h | 77 ++ ginac/simp_lor.cpp | 493 ++++++++ ginac/simp_lor.h | 152 +++ ginac/structure.cpp | 156 +++ ginac/structure.h | 70 ++ ginac/structure.pl | 483 ++++++++ ginac/symbol.cpp | 259 ++++ ginac/symbol.h | 111 ++ ginac/tinfos.h | 51 + ginac/utils.cpp | 98 ++ ginac/utils.h | 75 ++ ginsh/Makefile.am | 6 + ginsh/Makefile.in | 454 +++++-- ginsh/ginsh.h | 13 +- ginsh/{ginsh.l => ginsh_lexer.ll} | 15 +- ginsh/{ginsh.y => ginsh_parser.yy} | 6 +- ginsh/strdup.c | 10 + ltconfig | 0 ltmain.sh | 0 stamp-h.in | 0 121 files changed, 27264 insertions(+), 1342 deletions(-) create mode 100644 AUTHORS create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 acinclude.m4 create mode 100644 check/Makefile.am create mode 100755 check/run_checks create mode 100755 config.guess create mode 100755 config.sub delete mode 100644 doc/Makefile create mode 100644 doc/Makefile.am create mode 100644 ginac/Makefile.am create mode 100644 ginac/Makefile.in create mode 100644 ginac/add.cpp create mode 100644 ginac/add.h create mode 100644 ginac/basic.cpp create mode 100644 ginac/basic.h create mode 100644 ginac/clifford.cpp create mode 100644 ginac/clifford.h create mode 100644 ginac/color.cpp create mode 100644 ginac/color.h create mode 100644 ginac/coloridx.cpp create mode 100644 ginac/coloridx.h create mode 100644 ginac/constant.cpp create mode 100644 ginac/constant.h create mode 100755 ginac/container.pl create mode 100644 ginac/debugmsg.h create mode 100644 ginac/diff.cpp create mode 100644 ginac/ex.cpp create mode 100644 ginac/ex.h create mode 100644 ginac/expair.h create mode 100644 ginac/expairseq.cpp create mode 100644 ginac/expairseq.h create mode 100644 ginac/exprseq.cpp create mode 100644 ginac/exprseq.h create mode 100644 ginac/exprseq_suppl.cpp create mode 100644 ginac/fail.cpp create mode 100644 ginac/fail.h create mode 100644 ginac/flags.h create mode 100644 ginac/function.cpp create mode 100644 ginac/function.h create mode 100755 ginac/function.pl create mode 100644 ginac/ginac.h create mode 100644 ginac/idx.cpp create mode 100644 ginac/idx.h create mode 100644 ginac/indexed.cpp create mode 100644 ginac/indexed.h create mode 100644 ginac/inifcns.cpp create mode 100644 ginac/inifcns.h create mode 100644 ginac/inifcns_gamma.cpp create mode 100644 ginac/inifcns_trans.cpp create mode 100644 ginac/isospin.cpp create mode 100644 ginac/isospin.h create mode 100644 ginac/lorentzidx.cpp create mode 100644 ginac/lorentzidx.h create mode 100644 ginac/lst.cpp create mode 100644 ginac/lst.h create mode 100644 ginac/lst_suppl.cpp create mode 100644 ginac/matrix.cpp create mode 100644 ginac/matrix.h create mode 100644 ginac/mul.cpp create mode 100644 ginac/mul.h create mode 100644 ginac/ncmul.cpp create mode 100644 ginac/ncmul.h create mode 100644 ginac/normal.cpp create mode 100644 ginac/normal.h create mode 100644 ginac/numeric.cpp create mode 100644 ginac/numeric.h create mode 100644 ginac/operators.cpp create mode 100644 ginac/operators.h create mode 100644 ginac/power.cpp create mode 100644 ginac/power.h create mode 100644 ginac/print.cpp create mode 100644 ginac/printcsrc.cpp create mode 100644 ginac/printraw.cpp create mode 100644 ginac/printtree.cpp create mode 100644 ginac/relational.cpp create mode 100644 ginac/relational.h create mode 100644 ginac/series.cpp create mode 100644 ginac/series.h create mode 100644 ginac/simp_lor.cpp create mode 100644 ginac/simp_lor.h create mode 100644 ginac/structure.cpp create mode 100644 ginac/structure.h create mode 100755 ginac/structure.pl create mode 100644 ginac/symbol.cpp create mode 100644 ginac/symbol.h create mode 100644 ginac/tinfos.h create mode 100644 ginac/utils.cpp create mode 100644 ginac/utils.h create mode 100644 ginsh/Makefile.am rename ginsh/{ginsh.l => ginsh_lexer.ll} (96%) rename ginsh/{ginsh.y => ginsh_parser.yy} (99%) create mode 100644 ginsh/strdup.c create mode 100755 ltconfig create mode 100644 ltmain.sh create mode 100644 stamp-h.in diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..e69de29b diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..e69de29b diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..2f5ce758 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +## Process this file with automake to produce Makefile.in +SUBDIRS = ginac check ginsh doc diff --git a/Makefile.in b/Makefile.in index bcf90630..b3e55f26 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,134 +1,335 @@ -# This is the prototype Makefile for the GiNaC package. +# Makefile.in generated automatically by automake 1.3 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. -# Not every make knows what CXX is, so we inherit it together with some other -# values from configure which checks it anyways: -CXX = @CXX@ -CXXFLAGS = @CXXFLAGS@ -CPPFLAGS = @CPPFLAGS@ -DEFS = @DEFS@ -LIBS = @LIBS@ -LDFLAGS = @LDFLAGS@ -# Here come the usual install directories in GNU-configure fashion: +SHELL = /bin/sh + srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ + bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ libdir = @libdir@ -includedir = @includedir@/GiNaC - -# This must be empty unless the user has called configure with --enable-shared: -shared = @shared@ - -# The version-number is tracked in configure.in only: -LIBGINACVER = @LibGiNaC_Ver@ - -# Autoconf macro AC_PROC_INSTALL sets these: -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ - - -all: lib ginsh/ginsh - echo "now type make install" - -src/libginac.la: - cd src; ${MAKE} libginac.la - -src/.libs/libginac.a: - cd src; ${MAKE} .libs/libginac.a - -lib: - cd src; ${MAKE} all - - -# Targets for making the GiNaC interactive shell (ginsh) -ginsh: ginsh/ginsh - -ginsh/ginsh: - if [ "${shared}" ]; then \ - ${MAKE} sharedginsh; \ - else \ - ${MAKE} staticginsh; \ - fi +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include -sharedginsh: src/libginac.la - cd ginsh; ${MAKE} sharedginsh +DISTDIR = -staticginsh: src/.libs/libginac.a - cd ginsh; ${MAKE} staticginsh +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . -# Target for running a test-suite across the library: -check: - if [ "${shared}" ]; then \ - ${MAKE} sharedcheck; \ - else \ - ${MAKE} staticcheck; \ - fi - -sharedcheck: src/libginac.la - cd check; ${MAKE} sharedcheck - -staticcheck: src/.libs/libginac.a - cd check; ${MAKE} staticcheck - - -# Targets for installation in install directories. The user-visible target -# `install' determines which one to call (static lib only or both shared and -# static lib). -install: installdirs - @ if [ "${shared}" ]; then \ - ${MAKE} sharedinst; \ - else \ - ${MAKE} staticinst; \ - fi - ${INSTALL_DATA} include/GiNaC/*.h ${includedir}/ - cd ginsh; ${MAKE} install - cd doc; ${MAKE} install - -sharedinst: src/libginac.la - ${LIBTOOL} install src/libginac.la ${libdir}/libginac.la - ${LIBTOOL} -n --finish ${libdir} - -staticinst: src/.libs/libginac.a - ${INSTALL_DATA} src/.libs/libginac.a ${libdir}/libginac.a - -installdirs: - ./mkinstalldirs ${libdir} ${includedir} - - -# Targets for cleaning up. (clean deletes files created by built, distclean -# deletes files created by configuration, uninstall removes all files related -# to GiNaC from the system.) -clean: - cd src; ${MAKE} clean - cd check; ${MAKE} clean - cd ginsh; ${MAKE} clean - -distclean: clean - cd src; ${MAKE} distclean - cd check; ${MAKE} distclean - cd ginsh; ${MAKE} distclean - rm -f config.status config.log config.cache config.h Makefile - -uninstall: - rm -f ${libdir}/libginac.* - rm -rf ${includedir} - cd ginsh; ${MAKE} uninstall - cd doc; ${MAKE} uninstall - - -# Convenient targets for those who wish to extend on the documentation: -doc: - cd doc; ${MAKE} all -reference: - cd doc; ${MAKE} reference -tutorial: - cd doc; ${MAKE} tutorial - - -# Special dummy targets: -.PHONY: clean distclean all install installdirs uninstall check ginsh doc -.SUFFIXES: .o .lo .cpp -.SILENT: all check sharedcheck staticcheck doc reference tutorial +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +CC = @CC@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DOXYGEN = @DOXYGEN@ +DVIPS = @DVIPS@ +FIG2DEV = @FIG2DEV@ +JADE = @JADE@ +JADETEX = @JADETEX@ +LATEX = @LATEX@ +LD = @LD@ +LEX = @LEX@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINDEX = @MAKEINDEX@ +MAKEINFO = @MAKEINFO@ +NM = @NM@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = ginac check ginsh doc +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \ +Makefile.in NEWS acconfig.h acinclude.m4 aclocal.m4 config.guess \ +config.h.in config.sub configure configure.in install-sh ltconfig \ +ltmain.sh missing mkinstalldirs stamp-h.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP = --best +all: all-recursive-am all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): @MAINT@ configure.in acinclude.m4 + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure + $(SHELL) ./config.status --recheck +$(srcdir)/configure: @MAINT@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +config.h: stamp-h + @: +stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=config.h \ + $(SHELL) ./config.status + @echo timestamp > stamp-h +$(srcdir)/config.h.in: @MAINT@$(srcdir)/stamp-h.in +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + target=`echo $@ | sed s/-recursive//`; \ + echo "Making $$target in $$subdir"; \ + (cd $$subdir && $(MAKE) $$target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + done; \ + for subdir in $$rev; do \ + target=`echo $@ | sed s/-recursive//`; \ + echo "Making $$target in $$subdir"; \ + (cd $$subdir && $(MAKE) $$target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + (cd $$subdir && $(MAKE) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) \ + && $(MAKE) dvi \ + && $(MAKE) check \ + && $(MAKE) install \ + && $(MAKE) installcheck \ + && $(MAKE) dist + -rm -rf $(distdir) + @echo "========================"; \ + echo "$(distdir).tar.gz is ready for distribution"; \ + echo "========================" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done + for subdir in $(SUBDIRS); do \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + done +info: info-recursive +dvi: dvi-recursive +check: all-am + $(MAKE) check-recursive +installcheck: installcheck-recursive +all-recursive-am: config.h + $(MAKE) all-recursive + +all-am: Makefile config.h + +install-exec: install-exec-recursive + @$(NORMAL_INSTALL) + +install-data: install-data-recursive + @$(NORMAL_INSTALL) + +install: install-recursive + @: + +uninstall: uninstall-recursive + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: installdirs-recursive + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic + +clean-am: clean-hdr clean-tags clean-generic mostlyclean-am + +distclean-am: distclean-hdr distclean-tags distclean-generic clean-am + +maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \ + maintainer-clean-generic distclean-am + +mostlyclean: mostlyclean-recursive mostlyclean-am + +clean: clean-recursive clean-am + +distclean: distclean-recursive distclean-am + -rm -f config.status + -rm -f libtool + +maintainer-clean: maintainer-clean-recursive maintainer-clean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +install-data-recursive uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info dvi \ +installcheck all-recursive-am all-am install-exec install-data install \ +uninstall all installdirs mostlyclean-generic distclean-generic \ +clean-generic maintainer-clean-generic clean mostlyclean distclean \ +maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..e69de29b diff --git a/README b/README new file mode 100644 index 00000000..e69de29b diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..fff18399 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,116 @@ +dnl =========================================================================== +dnl Additional macros used to configure GiNaC. We don't start additions' names +dnl with AC_ but with GINAC_ in order to avoid future trouble. +dnl =========================================================================== + +dnl Generally, it is a bad idea to put specialized header files for a library +dnl into a generic directory like /usr/local/include/. Instead, one should put +dnl them into a subdirectory. GiNaC does it, NTL does it. Unfortunately, CLN +dnl doesn't do so but some people choose to do it by hand. In these cases we +dnl need to #include , otherwise #include . 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 ], + [factorial(1);], + ginac_cv_lib_cln_link="-lcln", + ginac_cv_lib_cln_link="fail") + ;; + *) + AC_TRY_LINK([#include ], + [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 +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 +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 +]) diff --git a/aclocal.m4 b/aclocal.m4 index fff18399..289b92e7 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,3 +1,15 @@ +dnl aclocal.m4 generated automatically by aclocal 1.3 + +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + dnl =========================================================================== dnl Additional macros used to configure GiNaC. We don't start additions' names dnl with AC_ but with GINAC_ in order to avoid future trouble. @@ -114,3 +126,398 @@ dnl should never ever get here: ;; esac ]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; 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 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AM_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AM_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[case "$NM" in +/* | [A-Za-z]:\\*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; +*) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + else + ac_cv_path_NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm + ;; +esac]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +AC_SUBST(NM) +]) + + +dnl AM_PROG_LEX +dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT +AC_DEFUN(AM_PROG_LEX, +[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1) +AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex") +AC_PROG_LEX +AC_DECL_YYTEXT]) + diff --git a/check/Makefile.am b/check/Makefile.am new file mode 100644 index 00000000..36d5f97b --- /dev/null +++ b/check/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in +noinst_PROGRAMS = check_ginac +check_ginac_SOURCES = paranoia_check.cpp numeric_output.cpp numeric_consist.cpp \ + powerlaws.cpp expand_subs.cpp inifcns_consist.cpp differentiation.cpp \ + poly_gcd.cpp normalization.cpp lsolve_onedim.cpp matrix_checks.cpp \ + series_expansion.cpp fcntimer.cpp main.cpp +check_ginac_LDADD = ../ginac/libginac.la +TESTS = run_checks diff --git a/check/Makefile.in b/check/Makefile.in index be0c4100..2cb92906 100644 --- a/check/Makefile.in +++ b/check/Makefile.in @@ -1,58 +1,358 @@ -# 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: diff --git a/check/check.h b/check/check.h index 68622d96..964df6bf 100644 --- a/check/check.h +++ b/check/check.h @@ -1,7 +1,7 @@ // check/check.h -#ifndef _CHECK_H_ -#define _CHECK_H_ +#ifndef CHECK_H +#define CHECK_H // fcntimer is defined in timer.cpp and used for timing check functions only: unsigned fcntimer(unsigned fcn()); @@ -21,4 +21,4 @@ unsigned matrix_checks(); unsigned lsolve_onedim(); unsigned series_expansion(); -#endif // ndef _CHECK_H_ +#endif // ndef CHECK_H diff --git a/check/differentiation.cpp b/check/differentiation.cpp index 6537eb3f..c6838efd 100644 --- a/check/differentiation.cpp +++ b/check/differentiation.cpp @@ -2,7 +2,7 @@ /* Tests for symbolic differentiation, including various functions. */ -#include +#include static unsigned check_diff(const ex &e, const symbol &x, const ex &d, unsigned nth=1) diff --git a/check/expand_subs.cpp b/check/expand_subs.cpp index e29e1777..9f4105a1 100644 --- a/check/expand_subs.cpp +++ b/check/expand_subs.cpp @@ -12,7 +12,7 @@ * substitute a0 by -a1 in e * after which e should return 0 (without expanding). */ -#include +#include #define VECSIZE 100 diff --git a/check/inifcns_consist.cpp b/check/inifcns_consist.cpp index 8eaf15fc..d85bf95e 100644 --- a/check/inifcns_consist.cpp +++ b/check/inifcns_consist.cpp @@ -3,7 +3,7 @@ /* This test routine applies assorted tests on initially known higher level * functions. */ -#include +#include /* Simple tests on the sine trigonometric function. */ static unsigned inifcns_consist_sin(void) diff --git a/check/lsolve_onedim.cpp b/check/lsolve_onedim.cpp index f2dc8c06..270b9eb1 100644 --- a/check/lsolve_onedim.cpp +++ b/check/lsolve_onedim.cpp @@ -3,7 +3,7 @@ /* This test routine does some simple checks on solving a polynomial for a * variable. */ -#include +#include unsigned lsolve_onedim(void) { diff --git a/check/main.cpp b/check/main.cpp index 787f9208..4cf44c6d 100644 --- a/check/main.cpp +++ b/check/main.cpp @@ -1,7 +1,7 @@ // check/main.cpp #include -#include +#include #include "check.h" int main() @@ -25,6 +25,7 @@ int main() } } catch (exception const & e) { cout << "error: caught an exception: " << e.what() << endl; + result++; } if (result) { diff --git a/check/matrix_checks.cpp b/check/matrix_checks.cpp index 4be5af73..db2277f5 100644 --- a/check/matrix_checks.cpp +++ b/check/matrix_checks.cpp @@ -3,7 +3,7 @@ /* Here we test manipulations on GiNaC's symbolic matrices. */ #include -#include +#include static unsigned matrix_determinants(void) { diff --git a/check/normalization.cpp b/check/normalization.cpp index 89809c1a..b3882e60 100644 --- a/check/normalization.cpp +++ b/check/normalization.cpp @@ -2,7 +2,7 @@ /* Rational function normalization test-suite. */ -#include +#include static symbol x("x"), y("y"), z("z"); diff --git a/check/numeric_consist.cpp b/check/numeric_consist.cpp index 9f558295..947c850a 100644 --- a/check/numeric_consist.cpp +++ b/check/numeric_consist.cpp @@ -4,7 +4,7 @@ * boolean tests on these numbers like is_integer() etc... */ #include -#include +#include /* Simple and maybe somewhat pointless consistency tests of assorted tests and * conversions. */ diff --git a/check/numeric_output.cpp b/check/numeric_output.cpp index f35663ea..c4806768 100644 --- a/check/numeric_output.cpp +++ b/check/numeric_output.cpp @@ -1,6 +1,6 @@ // check/numeric_output.cpp -#include +#include unsigned numeric_output(void) { diff --git a/check/paranoia_check.cpp b/check/paranoia_check.cpp index 6504bd85..97ee011d 100644 --- a/check/paranoia_check.cpp +++ b/check/paranoia_check.cpp @@ -5,7 +5,7 @@ * a sick behaviour again. But since we are paranoic and we want to exclude * that behaviour for good... */ -#include +#include // 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 diff --git a/check/poly_gcd.cpp b/check/poly_gcd.cpp index ee8b63d4..48425448 100644 --- a/check/poly_gcd.cpp +++ b/check/poly_gcd.cpp @@ -3,7 +3,7 @@ /* Some test with polynomial GCD calculations. See also the checks for * rational function normalization in normalization.cpp. */ -#include +#include const int MAX_VARIABLES = 5; diff --git a/check/powerlaws.cpp b/check/powerlaws.cpp index 3dc867df..e103fed9 100644 --- a/check/powerlaws.cpp +++ b/check/powerlaws.cpp @@ -3,7 +3,7 @@ /* Tests for power laws. You shouldn't try to draw much inspiration from * this code, it is a sanity check rather deeply rooted in GiNaC's classes. */ -#include +#include static unsigned powerlaws1(void) { diff --git a/check/run_checks b/check/run_checks new file mode 100755 index 00000000..1c9e6bab --- /dev/null +++ b/check/run_checks @@ -0,0 +1,5 @@ +#! /bin/sh +echo "Running checks..." +./check_ginac 2>result.out +echo "Comparing output..." +cmp result.ref result.out diff --git a/check/series_expansion.cpp b/check/series_expansion.cpp index b5cc110c..e66059de 100644 --- a/check/series_expansion.cpp +++ b/check/series_expansion.cpp @@ -2,7 +2,7 @@ /* Series expansion test (Laurent and Taylor series). */ -#include +#include static symbol x("x"); diff --git a/config.guess b/config.guess new file mode 100755 index 00000000..e69de29b diff --git a/config.h.in b/config.h.in index a60a0fc1..2be7888b 100644 --- a/config.h.in +++ b/config.h.in @@ -1,11 +1,14 @@ /* config.h.in. Generated automatically from configure.in by autoheader. */ -/* Define if you have the ANSI C header files. */ -#undef STDC_HEADERS - /* Define if lex declares yytext as a char * by default, not a char[]. */ #undef YYTEXT_POINTER +/* Define to the name of the distribution. */ +#undef PACKAGE + +/* Define to the version of the distribution. */ +#undef VERSION + /* Define if you have the strdup function. */ #undef HAVE_STRDUP diff --git a/config.sub b/config.sub new file mode 100755 index 00000000..e69de29b diff --git a/configure b/configure index 4f04a4ca..158683c2 100755 --- a/configure +++ b/configure @@ -1,7 +1,7 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf version 2.13 +# Generated automatically using autoconf version 2.12 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation @@ -12,8 +12,18 @@ ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help - --enable-shared build shared libraries [default=no] - (a static library will still be built as well)" + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer" +ac_help="$ac_help + --enable-shared build shared libraries [default=yes] + --enable-shared=PKGS only build shared libraries if the current package + appears as an element in the PKGS list" +ac_help="$ac_help + --enable-static build static libraries [default=yes] + --enable-static=PKGS only build shared libraries if the current package + appears as an element in the PKGS list" +ac_help="$ac_help + --with-gnu-ld assume the C compiler uses GNU ld [default=no]" # Initialize some variables set by options. # The variables have the same names as the options, with @@ -52,7 +62,6 @@ mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= -SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 @@ -336,7 +345,7 @@ EOF verbose=yes ;; -version | --version | --versio | --versi | --vers) - echo "configure generated by autoconf version 2.13" + echo "configure generated by autoconf version 2.12" exit 0 ;; -with-* | --with-*) @@ -454,7 +463,7 @@ echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. -ac_unique_file=include/GiNaC/ginac.h +ac_unique_file=ginac/basic.cpp # Find the source files, if location was not specified. if test -z "$srcdir"; then @@ -506,11 +515,9 @@ ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross -ac_exeext= -ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then @@ -526,36 +533,293 @@ fi -GiNaC_Major_Version=0 -GiNaC_Minor_Version=0 -GiNaC_Micro_Version=40 -GiNaC_Version="${GiNaC_Major_Version}.${GiNaC_Minor_Version}.${GiNaC_Micro_Version}" -LibGiNaC_Ver="${GiNaC_Major_Version}:${GiNaC_Micro_Version}:${GiNaC_Minor_Version}" -# Check whether --enable-shared or --disable-shared was given. -if test "${enable_shared+set}" = set; then - enableval="$enable_shared" - shared=${enableval} + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:570: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:623: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:680: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=GiNaC + +VERSION=0.4 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:726: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:739: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:752: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:765: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 else - shared="no" + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 fi +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:778: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + +echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 +echo "configure:792: checking whether to enable maintainer-specific portions of Makefiles" >&5 + # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" + USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6 + if test $USE_MAINTAINER_MODE = yes; then + MAINT= + else + MAINT='#M#' + fi + + -for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +for ac_prog in $CCC c++ g++ gcc CC cxx cc++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:550: checking for $ac_word" >&5 +echo "configure:815: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CXX="$ac_prog" @@ -578,23 +842,21 @@ test -n "$CXX" || CXX="gcc" echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:582: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo "configure:846: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 ac_ext=C # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +ac_link='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cxx_cross -cat > conftest.$ac_ext << EOF - -#line 593 "configure" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:860: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then ac_cv_prog_cxx_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -612,7 +874,7 @@ ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 @@ -620,12 +882,12 @@ if test $ac_cv_prog_cxx_works = no; then { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:624: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:886: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 cross_compiling=$ac_cv_prog_cxx_cross echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 -echo "configure:629: checking whether we are using GNU C++" >&5 +echo "configure:891: checking whether we are using GNU C++" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -634,7 +896,7 @@ else yes; #endif EOF -if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:638: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:900: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gxx=yes else ac_cv_prog_gxx=no @@ -645,15 +907,11 @@ echo "$ac_t""$ac_cv_prog_gxx" 1>&6 if test $ac_cv_prog_gxx = yes; then GXX=yes -else - GXX= -fi - -ac_test_CXXFLAGS="${CXXFLAGS+set}" -ac_save_CXXFLAGS="$CXXFLAGS" -CXXFLAGS= -echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 -echo "configure:657: checking whether ${CXX-g++} accepts -g" >&5 + ac_test_CXXFLAGS="${CXXFLAGS+set}" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS= + echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:915: checking whether ${CXX-g++} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -668,24 +926,20 @@ rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS="$ac_save_CXXFLAGS" -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" + elif test $ac_cv_prog_cxx_g = yes; then CXXFLAGS="-g -O2" else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then CXXFLAGS="-O2" - else - CXXFLAGS= fi +else + GXX= + test "${CXXFLAGS+set}" = set || CXXFLAGS="-g" fi echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6 -echo "configure:689: checking how to run the C++ preprocessor" >&5 +echo "configure:943: checking how to run the C++ preprocessor" >&5 if test -z "$CXXCPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -694,17 +948,17 @@ else # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +ac_link='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cxx_cross CXXCPP="${CXX-g++} -E" cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:707: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +{ (eval echo configure:961: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else @@ -720,530 +974,585 @@ ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross fi fi CXXCPP="$ac_cv_prog_CXXCPP" echo "$ac_t""$CXXCPP" 1>&6 -ac_ext=C -# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' -cross_compiling=$ac_cv_prog_cxx_cross -echo $ac_n "checking for cout in -lstdc++""... $ac_c" 1>&6 -echo "configure:739: checking for cout in -lstdc++" >&5 -ac_lib_var=`echo stdc++'_'cout | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lstdc++ $LIBS" -cat > conftest.$ac_ext <&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 <&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 -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 <&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 -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 <&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 -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 <&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 < -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 < conftest.$ac_ext < -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 < conftest.c < -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 < -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 &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 < +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 < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1488: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +missing_dir=`cd $ac_aux_dir && pwd` +for ac_prog in flex lex +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1193: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_path_LIBTOOL'+set}'`\" = set"; then +echo "configure:1516: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else - case "$LIBTOOL" in - /*) - ac_cv_path_LIBTOOL="$LIBTOOL" # Let the user override the test with a path. - ;; - ?:/*) - ac_cv_path_LIBTOOL="$LIBTOOL" # Let the user override the test with a dos path. - ;; - *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then - ac_cv_path_LIBTOOL="$ac_dir/$ac_word" + ac_cv_prog_LEX="$ac_prog" break fi done IFS="$ac_save_ifs" - test -z "$ac_cv_path_LIBTOOL" && ac_cv_path_LIBTOOL="""" - ;; -esac fi -LIBTOOL="$ac_cv_path_LIBTOOL" -if test -n "$LIBTOOL"; then - echo "$ac_t""$LIBTOOL" 1>&6 +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 else echo "$ac_t""no" 1>&6 fi - if test "${LIBTOOL}" == ""; then - echo "configure: warning: libtool not found: building static lib only" 1>&2 - shared=""; - fi - ;; -*) # Default, default-disable ("no") or user entered bogus: - shared=""; - ;; -esac +test -n "$LEX" && break +done +test -n "$LEX" || LEX=""$missing_dir/missing flex"" + # Extract the first word of "flex", so it can be a program name with args. set dummy flex; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1238: checking for $ac_word" >&5 +echo "configure:1548: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_LEX="flex" @@ -1268,7 +1577,7 @@ then *) ac_lib=l ;; esac echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 -echo "configure:1272: checking for yywrap in -l$ac_lib" >&5 +echo "configure:1581: checking for yywrap in -l$ac_lib" >&5 ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1276,12 +1585,9 @@ else ac_save_LIBS="$LIBS" LIBS="-l$ac_lib $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1600: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1312,21 +1618,82 @@ fi fi +echo $ac_n "checking lex output file root""... $ac_c" 1>&6 +echo "configure:1623: checking lex output file root" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # The minimal lex program is just a single line: %%. But some broken lexes +# (Solaris, I think it was) want two %% lines, so accommodate them. +echo '%% +%%' | $LEX +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; } +fi +fi + +echo "$ac_t""$ac_cv_prog_lex_root" 1>&6 +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6 +echo "configure:1644: checking whether yytext is a pointer" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c +ac_save_LIBS="$LIBS" +LIBS="$LIBS $LEXLIB" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + ac_cv_prog_lex_yytext_pointer=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +LIBS="$ac_save_LIBS" +rm -f "${LEX_OUTPUT_ROOT}.c" + +fi + +echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6 +if test $ac_cv_prog_lex_yytext_pointer = yes; then + cat >> confdefs.h <<\EOF +#define YYTEXT_POINTER 1 +EOF + +fi + for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1321: checking for $ac_word" >&5 +echo "configure:1689: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_YACC="$ac_prog" @@ -1342,196 +1709,369 @@ if test -n "$YACC"; then else echo "$ac_t""no" 1>&6 fi - -test -n "$YACC" && break + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + +echo $ac_n "checking for cout in -lstdc++""... $ac_c" 1>&6 +echo "configure:1728: checking for cout in -lstdc++" >&5 +ac_lib_var=`echo stdc++'_'cout | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lstdc++ $LIBS" +cat > conftest.$ac_ext <&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 <&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 +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 <&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 < conftest.$ac_ext < 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 <&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 < -#include -#include -#include +#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 <&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 <&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 < +#include +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 < conftest.$ac_ext < +#include +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 < -#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 +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 < +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 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1534: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +{ (eval echo configure:2074: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" @@ -1559,12 +2099,12 @@ done for ac_func in strdup do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1563: checking for $ac_func" >&5 +echo "configure:2103: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2134: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1611,25 +2151,27 @@ EOF else echo "$ac_t""no" 1>&6 +LIBOBJS="$LIBOBJS ${ac_func}.o" fi done + for ac_hdr in readline/readline.h readline/history.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1622: checking for $ac_hdr" >&5 +echo "configure:2164: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1632: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +{ (eval echo configure:2174: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" @@ -1651,12 +2193,11 @@ EOF else echo "$ac_t""no" 1>&6 -{ echo "configure: error: need to have GNU readline headers" 1>&2; exit 1; } fi done echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 -echo "configure:1660: checking for readline in -lreadline" >&5 +echo "configure:2201: checking for readline in -lreadline" >&5 ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1664,7 +2205,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lreadline $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2223: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1703,13 +2244,13 @@ EOF else echo "$ac_t""no" 1>&6 -{ echo "configure: error: need to have GNU readline library" 1>&2; exit 1; } fi + # Extract the first word of "doxygen", so it can be a program name with args. set dummy doxygen; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1713: checking for $ac_word" >&5 +echo "configure:2254: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_DOXYGEN'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1717,13 +2258,9 @@ else /*) ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a path. ;; - ?:/*) - ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a dos path. - ;; *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_DOXYGEN="$ac_dir/$ac_word" @@ -1745,7 +2282,7 @@ fi # Extract the first word of "latex", so it can be a program name with args. set dummy latex; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1749: checking for $ac_word" >&5 +echo "configure:2286: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_LATEX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1753,13 +2290,9 @@ else /*) ac_cv_path_LATEX="$LATEX" # Let the user override the test with a path. ;; - ?:/*) - ac_cv_path_LATEX="$LATEX" # Let the user override the test with a dos path. - ;; *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_LATEX="$ac_dir/$ac_word" @@ -1781,7 +2314,7 @@ fi # Extract the first word of "makeindex", so it can be a program name with args. set dummy makeindex; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1785: checking for $ac_word" >&5 +echo "configure:2318: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_MAKEINDEX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1789,13 +2322,9 @@ else /*) ac_cv_path_MAKEINDEX="$MAKEINDEX" # Let the user override the test with a path. ;; - ?:/*) - ac_cv_path_MAKEINDEX="$MAKEINDEX" # Let the user override the test with a dos path. - ;; *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_MAKEINDEX="$ac_dir/$ac_word" @@ -1817,7 +2346,7 @@ fi # Extract the first word of "dvips", so it can be a program name with args. set dummy dvips; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1821: checking for $ac_word" >&5 +echo "configure:2350: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_DVIPS'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1825,13 +2354,9 @@ else /*) ac_cv_path_DVIPS="$DVIPS" # Let the user override the test with a path. ;; - ?:/*) - ac_cv_path_DVIPS="$DVIPS" # Let the user override the test with a dos path. - ;; *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_DVIPS="$ac_dir/$ac_word" @@ -1853,7 +2378,7 @@ fi # Extract the first word of "fig2dev", so it can be a program name with args. set dummy fig2dev; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1857: checking for $ac_word" >&5 +echo "configure:2382: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_FIG2DEV'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1861,13 +2386,9 @@ else /*) ac_cv_path_FIG2DEV="$FIG2DEV" # Let the user override the test with a path. ;; - ?:/*) - ac_cv_path_FIG2DEV="$FIG2DEV" # Let the user override the test with a dos path. - ;; *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_FIG2DEV="$ac_dir/$ac_word" @@ -1889,7 +2410,7 @@ fi # Extract the first word of "jade", so it can be a program name with args. set dummy jade; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1893: checking for $ac_word" >&5 +echo "configure:2414: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_JADE'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1897,13 +2418,9 @@ else /*) ac_cv_path_JADE="$JADE" # Let the user override the test with a path. ;; - ?:/*) - ac_cv_path_JADE="$JADE" # Let the user override the test with a dos path. - ;; *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_JADE="$ac_dir/$ac_word" @@ -1925,7 +2442,7 @@ fi # Extract the first word of "jadetex", so it can be a program name with args. set dummy jadetex; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1929: checking for $ac_word" >&5 +echo "configure:2446: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_JADETEX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1933,13 +2450,9 @@ else /*) ac_cv_path_JADETEX="$JADETEX" # Let the user override the test with a path. ;; - ?:/*) - ac_cv_path_JADETEX="$JADETEX" # Let the user override the test with a dos path. - ;; *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_JADETEX="$ac_dir/$ac_word" @@ -1959,9 +2472,6 @@ else fi - - - trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure @@ -1985,7 +2495,7 @@ EOF # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | - case `(ac_space=' '; set | grep ac_space) 2>&1` in + case `(ac_space=' '; set) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). @@ -2052,7 +2562,7 @@ do echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) - echo "$CONFIG_STATUS generated by autoconf version 2.13" + echo "$CONFIG_STATUS generated by autoconf version 2.12" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; @@ -2063,7 +2573,7 @@ done ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" -trap 'rm -fr `echo "Makefile src/Makefile check/Makefile ginsh/Makefile doc/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +trap 'rm -fr `echo "Makefile ginac/Makefile check/Makefile ginsh/Makefile doc/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub -s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g -s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g @@ -2095,17 +2603,37 @@ s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g -s%@CXX@%$CXX%g -s%@CXXCPP@%$CXXCPP%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g -s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g s%@INSTALL_DATA@%$INSTALL_DATA%g -s%@MAKEDEPEND@%$MAKEDEPEND%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@MAINT@%$MAINT%g +s%@CXX@%$CXX%g +s%@CXXCPP@%$CXXCPP%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@RANLIB@%$RANLIB%g +s%@CC@%$CC%g +s%@LD@%$LD%g +s%@NM@%$NM%g +s%@LN_S@%$LN_S%g s%@LIBTOOL@%$LIBTOOL%g s%@LEX@%$LEX%g s%@LEXLIB@%$LEXLIB%g -s%@YACC@%$YACC%g +s%@CPP@%$CPP%g s%@LEX_OUTPUT_ROOT@%$LEX_OUTPUT_ROOT%g +s%@YACC@%$YACC%g +s%@LIBOBJS@%$LIBOBJS%g s%@DOXYGEN@%$DOXYGEN%g s%@LATEX@%$LATEX%g s%@MAKEINDEX@%$MAKEINDEX%g @@ -2113,8 +2641,6 @@ s%@DVIPS@%$DVIPS%g s%@FIG2DEV@%$FIG2DEV%g s%@JADE@%$JADE%g s%@JADETEX@%$JADETEX%g -s%@shared@%$shared%g -s%@LibGiNaC_Ver@%$LibGiNaC_Ver%g CEOF EOF @@ -2156,7 +2682,7 @@ EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then @@ -2325,8 +2851,10 @@ fi; done EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h exit 0 EOF @@ -2334,4 +2862,4 @@ chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 -echo "now type make" +echo "Configuration done. Now type \"make\"." diff --git a/configure.in b/configure.in index 069bb727..a846c91e 100644 --- a/configure.in +++ b/configure.in @@ -1,82 +1,47 @@ -dnl =========================================================================== -dnl Process this file with GNU Autoconf to produce a configure script. Then -dnl call ./configure to create Makefiles. After that say make and make install. -dnl See aclocal.m4 for additional self-made macros. -dnl =========================================================================== +dnl Process this file with autoconf to produce a configure script. -dnl This file is used as a signal that everything is in place: -AC_INIT(include/GiNaC/ginac.h) -dnl A convenient header file for some additional system-dependend output: -AC_CONFIG_HEADER(config.h) +AC_INIT(ginac/basic.cpp) +AM_CONFIG_HEADER(config.h) +AC_PREREQ(2.12) -dnl Set the Version Number at this place only: -GiNaC_Major_Version=0 -GiNaC_Minor_Version=0 -GiNaC_Micro_Version=40 -dnl This composite variable can be inserted where it appears necessary: -GiNaC_Version="${GiNaC_Major_Version}.${GiNaC_Minor_Version}.${GiNaC_Micro_Version}" -dnl This composition is needed for libtool, if a shared lib shall be built: -LibGiNaC_Ver="${GiNaC_Major_Version}:${GiNaC_Micro_Version}:${GiNaC_Minor_Version}" - -dnl =========================================================================== -dnl Several features need to be added to standard-configure: -dnl =========================================================================== -AC_ARG_ENABLE(shared, - [ --enable-shared build shared libraries [default=no] - (a static library will still be built as well)], - shared=${enableval}, shared="no") +dnl This defines PACKAGE and VERSION +AM_INIT_AUTOMAKE([GiNaC], [0.4]) +AM_MAINTAINER_MODE dnl =========================================================================== dnl Check for the compiler and all the utilities needed for the build: dnl =========================================================================== -dnl Which is the C++ Compiler? (whether to use c++, g++, gcc, CC, cxx, cc++...) AC_PROG_CXX -dnl How to run the C++ preprocessor? AC_PROG_CXXCPP +AM_PROG_INSTALL +AM_PROG_LIBTOOL +AM_PROG_LEX +AC_PROG_YACC + dnl Switch to C++ language mode for the following libraries and headers: AC_LANG_CPLUSPLUS + dnl Make sure the following libraries work by testing for symbols therein. dnl They are automatically added the the variable $LIBS and thus passed into dnl the Makefile: AC_CHECK_LIB(stdc++, cout) + dnl Make sure all the necessary new-style headers are installed on the system. dnl If one of them cannot be found the system is probably not ANSI-conform dnl enough so trying the .h-style headers is a waste of time. AC_CHECK_HEADERS(iostream vector map string list typeinfo iterator strstream stdexcept algorithm, , AC_MSG_ERROR(need to have ANSI compliant headers)) + dnl We need to have Bruno Haible's CLN installed (macros are in aclocal.m4): GINAC_CHECK_CLN_H GINAC_CHECK_LIBCLN -dnl We need to distribure install-sh anyways since otherwise configure will -dnl refuse to do several things, like divert into subdirs and so: -AC_PROG_INSTALL -dnl Todd Brunhoff's makedepend utility is needed by make: -AC_PATH_PROG(MAKEDEPEND, makedepend, "") -dnl We need GNU libtool if the user chose to create a shared lib. (By using a -dnl little trick we can safely recycle the variable shlib which is later passed -dnl into the Makefile.) -case "${shared}" in -"yes"|"Yes"|"YES") # Default-enable ("yes") or user was nitpicking: - shared="shlib"; - AC_PATH_PROG(LIBTOOL, libtool, "") - if test "${LIBTOOL}" == ""; then - AC_MSG_WARN([libtool not found: building static lib only]) - shared=""; - fi - ;; -*) # Default, default-disable ("no") or user entered bogus: - shared=""; - ;; -esac -dnl Check for helpers needed for building the GiNaC interactive shell (ginsh): -AC_PROG_LEX -AC_PROG_YACC -AC_DECL_YYTEXT -AC_HEADER_STDC + +dnl Check for stuff needed for building the GiNaC interactive shell (ginsh): AC_CHECK_HEADERS(unistd.h) -AC_CHECK_FUNCS(strdup) -AC_CHECK_HEADERS(readline/readline.h readline/history.h, , AC_MSG_ERROR(need to have GNU readline headers)) -AC_CHECK_LIB(readline, readline, , AC_MSG_ERROR(need to have GNU readline library)) +AC_REPLACE_FUNCS(strdup) +AC_CHECK_HEADERS(readline/readline.h readline/history.h) +AC_CHECK_LIB(readline, readline) + dnl Check for utilities needed by the different kinds of documentation. dnl Documantation needs only be built when extending it, so never mind if it dnl cannot find those helpers: @@ -88,14 +53,8 @@ AC_PATH_PROG(FIG2DEV, fig2dev, "") AC_PATH_PROG(JADE, jade, "") AC_PATH_PROG(JADETEX, jadetex, "") -dnl =========================================================================== -dnl Substitute these variables in the Makefile: -dnl =========================================================================== -AC_SUBST(shared) -AC_SUBST(LibGiNaC_Ver) - dnl =========================================================================== dnl Produce a Makefile from Makefile.in: dnl =========================================================================== -AC_OUTPUT([Makefile src/Makefile check/Makefile ginsh/Makefile doc/Makefile]) -echo "now type make" +AC_OUTPUT([Makefile ginac/Makefile check/Makefile ginsh/Makefile doc/Makefile]) +echo "Configuration done. Now type \"make\"." diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 66acd0f5..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,169 +0,0 @@ -# Generated automatically from Makefile.in by configure. -# This is the prototype Makefile for all of GiNaC's documentation. It tries to -# be tolerant---if some tools were not found it skips the built of that part -# of documentation and tries to continue. - -# Substitution variables from configure skript: -# Here come the usual install directories in GNU-configure fashion: -prefix = /usr/local -docdir = ${prefix}/share/doc/GiNaC -srcdir = . -# Dimitri van Heesch's Doxygen is needed for developer's resource: -DOXYGEN = /usr/local/bin_i386/doxygen -# LaTeX and friends are needed for processing developer's resource for print: -LATEX = /usr/local/bin/latex -MAKEINDEX = /usr/local/bin/makeindex -DVIPS = /usr/local/bin/dvips -FIG2DEV = /usr/bin/X11/fig2dev -# Jade and friends needed for generating the tutorial: -JADE = /usr/bin/jade -JADETEX = /usr/local/bin/jadetex -# Arguments for Jade and friends (does anybody know how to find them out?) -# JADEARGS_TEX = -t tex -o tutorial.tex -d /usr/lib/dsssl/stylesheets/docbook/print/docbook.dsl -JADEARGS_TEX = -t tex -o tutorial.tex -d /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl -# JADEARGS_HTML = -t sgml -d /usr/lib/dsssl/stylesheets/docbook/html/docbook.dsl -JADEARGS_HTML = -t sgml -d /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl -# Autoconf macro AC_PROC_INSTALL sets these: -INSTALL = /usr/bin/install -c -INSTALL_DATA = ${INSTALL} -m 644 -# All LaTeX builds will take place in a separate subdirectory: -VPATH = .:./latex:./tutorial - -# default target: -all: reference tutorial - -# REFERENCE: -# This section produces HTML'ed and TeX'ed developer's reference from the -# sources with a JavaDoc-like tool (in this case doxygen): -reference_html: - @ if [ ! -d ${srcdir}/reference ]; then mkdir ${srcdir}/reference; fi - @ if [ "${DOXYGEN}" ]; then \ - echo "Running ${DOXYGEN} ./DoxyfileHTML..."; \ - cd ..; ${DOXYGEN} ./doc/DoxyfileHTML; \ - else \ - echo "warning: target reference_html disabled by configuration"; \ - fi - -reference.tex: - @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi - @ if [ "${DOXYGEN}" ]; then \ - echo "Running ${DOXYGEN} ./DoxyfileTEX..."; \ - cd ..; ${DOXYGEN} ./doc/DoxyfileTEX; \ - else \ - echo "warning: target reference.tex disabled by configuration"; \ - fi - - mv ${srcdir}/latex/refman.tex ${srcdir}/latex/reference.tex - -reference.dvi: reference.tex - @ if [ "${LATEX}" -a "${MAKEINDEX}" ]; then \ - cd latex; \ - ${LATEX} reference.tex && \ - ${MAKEINDEX} reference.idx && \ - ${LATEX} reference.tex; \ - else \ - echo "warning: target reference.dvi disabled by configuration"; \ - fi - -reference.ps: reference.dvi - @ if [ "${DVIPS}" ]; then \ - echo "Running ${DVIPS} -o reference.ps reference.dvi..."; \ - cd latex; ${DVIPS} -o reference.ps reference.dvi; \ - else \ - echo "warning: target reference.ps disabled by configuration"; \ - fi - -reference: reference_html reference.ps - -# TUTORIAL: -# This section produces HTML'ed and TeX'ed versions of the tutorial using a -# SGML to TeX converter (in this case jade). As a dirty hack, we are doing -# some regexpese to tutorial.sgml prior to parsing it, in order to allow for -# different graphics output. This seems to be an ugly limitation of docbook... - -EPS = classhierarchy.eps rep_naive.eps rep_pair.eps -PNG = classhierarchy.png rep_naive.png rep_pair.png - -tutorial/index.html: tutorial.sgml.in ${PNG} - @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi - @ if [ "${JADE}" ]; then \ - sed -e 's/graext/png/g' -e 's/GRAEXT/GIF/g' tutorial.sgml.in > tutorial.sgml; \ - echo "Running ${JADE} ${JADEARGS_HTML} tutorial.sgml..."; \ - cd tutorial/; ${JADE} ${JADEARGS_HTML} ../tutorial.sgml; \ - if [ -f book1.html ]; then cp book1.html index.html; fi; \ - else \ - echo "warning: target tutorial_html disabled by configuration"; \ - fi - -tutorial.tex: tutorial.sgml.in ${EPS} - @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi - @ if [ "${JADE}" -a "${LATEX}" ]; then \ - sed -e 's/graext/eps/g' -e 's/GRAEXT/EPS/g' tutorial.sgml.in > tutorial.sgml; \ - echo "Running ${JADE} ${JADEARGS_TEX} tutorial.sgml..."; \ - cd latex; ${JADE} ${JADEARGS_TEX} ../tutorial.sgml ; \ - else \ - echo "warning: target tutorial.tex disabled by configuration"; \ - fi - -tutorial.dvi: tutorial.tex - @ if [ "${JADETEX}" ]; then \ - echo "Running ${JADETEX} tutorial.tex..."; \ - cd latex; ${JADETEX} tutorial.tex && ${JADETEX} tutorial.tex && ${JADETEX} tutorial.tex; \ - else \ - echo "warning: target tutorial.dvi disabled by configuration"; \ - fi - -tutorial.ps: tutorial.dvi - @ if [ "${DVIPS}" ]; then \ - echo "Running ${DVIPS} tutorial.dvi -o tutorial.ps..."; \ - cd latex; ${DVIPS} tutorial.dvi -o tutorial.ps; \ - else \ - echo "warning: target tutorial.ps disabled by configuration"; \ - fi - -tutorial: tutorial/index.html tutorial.ps - -# Target for installing all generated documentation files on the system. -# (Foolproof: installs what we got, even if one or more targets failed.) -install: - - ${INSTALL} -d ${docdir}/reference/ - - ${INSTALL_DATA} ${srcdir}/reference/* ${docdir}/reference/ - - ${INSTALL_DATA} ${srcdir}/latex/reference.ps ${docdir}/ - - ${INSTALL} -d ${docdir}/tutorial/ - - ${INSTALL_DATA} ${srcdir}/tutorial/* ${docdir}/tutorial/ - - ${INSTALL_DATA} ${srcdir}/latex/tutorial.ps ${docdir}/ - -# Removes all installed documentation files from the system: -uninstall: - rm -rf ${docdir} - -# The next targets should only be called in case of emergency by developers, -# since the complete documentation is not normally rebuilt. In any case, they -# should only be called from people who know what they are doing and never -# from top-level Makefile's targets clean and distclean. -clean: - rm -rf ${srcdir}/tutorial ${srcdir}/reference ${srcdir}/latex - rm -f tutorial.sgml - -distclean: clean - rm -f Makefile - -# Special dummy targets: -.SUFFIXES: .fig .eps .png -.PHONY: all clean distclean reference tutorial -.SILENT: all reference tutorial_html tutorial_tex - -# Suffix rules: -.fig.eps : - @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi - if [ "${FIG2DEV}" ]; then \ - ${FIG2DEV} -L ps -m 0.8 $< ${srcdir}/latex/$@; \ - else \ - echo "warning: fig2dev was not found by configure"; \ - fi -.fig.png : - @ if [ ! -d ${srcdir}/tutorial ]; then mkdir ${srcdir}/tutorial; fi - if [ "${FIG2DEV}" ]; then \ - ${FIG2DEV} -L png $< ${srcdir}/tutorial/$@; \ - else \ - echo "warning: fig2dev was not found by configure"; \ - fi diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 00000000..96d7a6ab --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1 @@ +## Process this file with automake to produce Makefile.in diff --git a/doc/Makefile.in b/doc/Makefile.in index ebe33f69..dad8d832 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -1,168 +1,178 @@ -# This is the prototype Makefile for all of GiNaC's documentation. It tries to -# be tolerant---if some tools were not found it skips the built of that part -# of documentation and tries to continue. +# Makefile.in generated automatically by automake 1.3 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh -# Substitution variables from configure skript: -# Here come the usual install directories in GNU-configure fashion: -prefix = @prefix@ -docdir = @datadir@/doc/GiNaC srcdir = @srcdir@ -# Dimitri van Heesch's Doxygen is needed for developer's resource: +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DISTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +CC = @CC@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ DOXYGEN = @DOXYGEN@ -# LaTeX and friends are needed for processing developer's resource for print: -LATEX = @LATEX@ -MAKEINDEX = @MAKEINDEX@ DVIPS = @DVIPS@ FIG2DEV = @FIG2DEV@ -# Jade and friends needed for generating the tutorial: JADE = @JADE@ JADETEX = @JADETEX@ -# Arguments for Jade and friends (does anybody know how to find them out?) -# JADEARGS_TEX = -t tex -o tutorial.tex -d /usr/lib/dsssl/stylesheets/docbook/print/docbook.dsl -JADEARGS_TEX = -t tex -o tutorial.tex -d /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl -# JADEARGS_HTML = -t sgml -d /usr/lib/dsssl/stylesheets/docbook/html/docbook.dsl -JADEARGS_HTML = -t sgml -d /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl -# Autoconf macro AC_PROC_INSTALL sets these: -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -# All LaTeX builds will take place in a separate subdirectory: -VPATH = @srcdir@:@srcdir@/latex:@srcdir@/tutorial - -# default target: -all: reference tutorial - -# REFERENCE: -# This section produces HTML'ed and TeX'ed developer's reference from the -# sources with a JavaDoc-like tool (in this case doxygen): -reference_html: - @ if [ ! -d ${srcdir}/reference ]; then mkdir ${srcdir}/reference; fi - @ if [ "${DOXYGEN}" ]; then \ - echo "Running ${DOXYGEN} ./DoxyfileHTML..."; \ - cd ..; ${DOXYGEN} ./doc/DoxyfileHTML; \ - else \ - echo "warning: target reference_html disabled by configuration"; \ - fi - -reference.tex: - @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi - @ if [ "${DOXYGEN}" ]; then \ - echo "Running ${DOXYGEN} ./DoxyfileTEX..."; \ - cd ..; ${DOXYGEN} ./doc/DoxyfileTEX; \ - else \ - echo "warning: target reference.tex disabled by configuration"; \ - fi - - mv ${srcdir}/latex/refman.tex ${srcdir}/latex/reference.tex - -reference.dvi: reference.tex - @ if [ "${LATEX}" -a "${MAKEINDEX}" ]; then \ - cd latex; \ - ${LATEX} reference.tex && \ - ${MAKEINDEX} reference.idx && \ - ${LATEX} reference.tex; \ - else \ - echo "warning: target reference.dvi disabled by configuration"; \ - fi - -reference.ps: reference.dvi - @ if [ "${DVIPS}" ]; then \ - echo "Running ${DVIPS} -o reference.ps reference.dvi..."; \ - cd latex; ${DVIPS} -o reference.ps reference.dvi; \ - else \ - echo "warning: target reference.ps disabled by configuration"; \ - fi - -reference: reference_html reference.ps - -# TUTORIAL: -# This section produces HTML'ed and TeX'ed versions of the tutorial using a -# SGML to TeX converter (in this case jade). As a dirty hack, we are doing -# some regexpese to tutorial.sgml prior to parsing it, in order to allow for -# different graphics output. This seems to be an ugly limitation of docbook... - -EPS = classhierarchy.eps rep_naive.eps rep_pair.eps -PNG = classhierarchy.png rep_naive.png rep_pair.png - -tutorial/index.html: tutorial.sgml.in ${PNG} - @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi - @ if [ "${JADE}" ]; then \ - sed -e 's/graext/png/g' -e 's/GRAEXT/GIF/g' tutorial.sgml.in > tutorial.sgml; \ - echo "Running ${JADE} ${JADEARGS_HTML} tutorial.sgml..."; \ - cd tutorial/; ${JADE} ${JADEARGS_HTML} ../tutorial.sgml; \ - if [ -f book1.html ]; then cp book1.html index.html; fi; \ - else \ - echo "warning: target tutorial_html disabled by configuration"; \ - fi - -tutorial.tex: tutorial.sgml.in ${EPS} - @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi - @ if [ "${JADE}" -a "${LATEX}" ]; then \ - sed -e 's/graext/eps/g' -e 's/GRAEXT/EPS/g' tutorial.sgml.in > tutorial.sgml; \ - echo "Running ${JADE} ${JADEARGS_TEX} tutorial.sgml..."; \ - cd latex; ${JADE} ${JADEARGS_TEX} ../tutorial.sgml ; \ - else \ - echo "warning: target tutorial.tex disabled by configuration"; \ - fi - -tutorial.dvi: tutorial.tex - @ if [ "${JADETEX}" ]; then \ - echo "Running ${JADETEX} tutorial.tex..."; \ - cd latex; ${JADETEX} tutorial.tex && ${JADETEX} tutorial.tex && ${JADETEX} tutorial.tex; \ - else \ - echo "warning: target tutorial.dvi disabled by configuration"; \ - fi - -tutorial.ps: tutorial.dvi - @ if [ "${DVIPS}" ]; then \ - echo "Running ${DVIPS} tutorial.dvi -o tutorial.ps..."; \ - cd latex; ${DVIPS} tutorial.dvi -o tutorial.ps; \ - else \ - echo "warning: target tutorial.ps disabled by configuration"; \ - fi - -tutorial: tutorial/index.html tutorial.ps - -# Target for installing all generated documentation files on the system. -# (Foolproof: installs what we got, even if one or more targets failed.) -install: - - ${INSTALL} -d ${docdir}/reference/ - - ${INSTALL_DATA} ${srcdir}/reference/* ${docdir}/reference/ - - ${INSTALL_DATA} ${srcdir}/latex/reference.ps ${docdir}/ - - ${INSTALL} -d ${docdir}/tutorial/ - - ${INSTALL_DATA} ${srcdir}/tutorial/* ${docdir}/tutorial/ - - ${INSTALL_DATA} ${srcdir}/latex/tutorial.ps ${docdir}/ - -# Removes all installed documentation files from the system: -uninstall: - rm -rf ${docdir} - -# The next targets should only be called in case of emergency by developers, -# since the complete documentation is not normally rebuilt. In any case, they -# should only be called from people who know what they are doing and never -# from top-level Makefile's targets clean and distclean. -clean: - rm -rf ${srcdir}/tutorial ${srcdir}/reference ${srcdir}/latex - rm -f tutorial.sgml - -distclean: clean - rm -f Makefile - -# Special dummy targets: -.SUFFIXES: .fig .eps .png -.PHONY: all clean distclean reference tutorial -.SILENT: all reference tutorial_html tutorial_tex - -# Suffix rules: -.fig.eps : - @ if [ ! -d ${srcdir}/latex ]; then mkdir ${srcdir}/latex; fi - if [ "${FIG2DEV}" ]; then \ - ${FIG2DEV} -L ps -m 0.8 $< ${srcdir}/latex/$@; \ - else \ - echo "warning: fig2dev was not found by configure"; \ - fi -.fig.png : - @ if [ ! -d ${srcdir}/tutorial ]; then mkdir ${srcdir}/tutorial; fi - if [ "${FIG2DEV}" ]; then \ - ${FIG2DEV} -L png $< ${srcdir}/tutorial/$@; \ - else \ - echo "warning: fig2dev was not found by configure"; \ - fi +LATEX = @LATEX@ +LD = @LD@ +LEX = @LEX@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINDEX = @MAKEINDEX@ +MAKEINFO = @MAKEINFO@ +NM = @NM@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP = --best +all: Makefile + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = doc + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu doc/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done +info: +dvi: +check: all + $(MAKE) +installcheck: +install-exec: + @$(NORMAL_INSTALL) + +install-data: + @$(NORMAL_INSTALL) + +install: install-exec install-data all + @: + +uninstall: + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-generic + +clean: clean-generic mostlyclean + +distclean: distclean-generic clean + -rm -f config.status + -rm -f libtool + +maintainer-clean: maintainer-clean-generic distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: tags distdir info dvi installcheck install-exec install-data \ +install uninstall all installdirs mostlyclean-generic distclean-generic \ +clean-generic maintainer-clean-generic clean mostlyclean distclean \ +maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ginac/Makefile.am b/ginac/Makefile.am new file mode 100644 index 00000000..d215d8ce --- /dev/null +++ b/ginac/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to produce Makefile.in +lib_LTLIBRARIES = libginac.la +libginac_la_SOURCES = add.cpp basic.cpp constant.cpp diff.cpp ex.cpp \ + expairseq.cpp exprseq.cpp fail.cpp function.cpp inifcns.cpp \ + inifcns_trans.cpp inifcns_gamma.cpp matrix.cpp mul.cpp normal.cpp \ + numeric.cpp operators.cpp power.cpp print.cpp printraw.cpp printtree.cpp \ + printcsrc.cpp relational.cpp symbol.cpp utils.cpp series.cpp ncmul.cpp \ + clifford.cpp structure.cpp color.cpp indexed.cpp idx.cpp isospin.cpp \ + exprseq_suppl.cpp lst.cpp lst_suppl.cpp simp_lor.cpp coloridx.cpp \ + lorentzidx.cpp utils.h +ginacincludedir = $(includedir)/ginac +ginacinclude_HEADERS = ginac.h add.h basic.h clifford.h color.h coloridx.h \ + constant.h debugmsg.h ex.h expair.h expairseq.h exprseq.h fail.h flags.h \ + function.h idx.h indexed.h inifcns.h isospin.h lorentzidx.h lst.h matrix.h \ + mul.h ncmul.h normal.h numeric.h operators.h power.h relational.h series.h \ + simp_lor.h structure.h symbol.h tinfos.h diff --git a/ginac/Makefile.in b/ginac/Makefile.in new file mode 100644 index 00000000..724c9714 --- /dev/null +++ b/ginac/Makefile.in @@ -0,0 +1,383 @@ +# Makefile.in generated automatically by automake 1.3 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DISTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +CC = @CC@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DOXYGEN = @DOXYGEN@ +DVIPS = @DVIPS@ +FIG2DEV = @FIG2DEV@ +JADE = @JADE@ +JADETEX = @JADETEX@ +LATEX = @LATEX@ +LD = @LD@ +LEX = @LEX@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINDEX = @MAKEINDEX@ +MAKEINFO = @MAKEINFO@ +NM = @NM@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +lib_LTLIBRARIES = libginac.la +libginac_la_SOURCES = add.cpp basic.cpp constant.cpp diff.cpp ex.cpp \ + expairseq.cpp exprseq.cpp fail.cpp function.cpp inifcns.cpp \ + inifcns_trans.cpp inifcns_gamma.cpp matrix.cpp mul.cpp normal.cpp \ + numeric.cpp operators.cpp power.cpp print.cpp printraw.cpp printtree.cpp \ + printcsrc.cpp relational.cpp symbol.cpp utils.cpp series.cpp ncmul.cpp \ + clifford.cpp structure.cpp color.cpp indexed.cpp idx.cpp isospin.cpp \ + exprseq_suppl.cpp lst.cpp lst_suppl.cpp simp_lor.cpp coloridx.cpp \ + lorentzidx.cpp utils.h +ginacincludedir = $(includedir)/ginac +ginacinclude_HEADERS = ginac.h add.h basic.h clifford.h color.h coloridx.h \ + constant.h debugmsg.h ex.h expair.h expairseq.h exprseq.h fail.h flags.h \ + function.h idx.h indexed.h inifcns.h isospin.h lorentzidx.h lst.h matrix.h \ + mul.h ncmul.h normal.h numeric.h operators.h power.h relational.h series.h \ + simp_lor.h structure.h symbol.h tinfos.h +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(lib_LTLIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libginac_la_LDFLAGS = +libginac_la_LIBADD = +libginac_la_OBJECTS = add.lo basic.lo constant.lo diff.lo ex.lo \ +expairseq.lo exprseq.lo fail.lo function.lo inifcns.lo inifcns_trans.lo \ +inifcns_gamma.lo matrix.lo mul.lo normal.lo numeric.lo operators.lo \ +power.lo print.lo printraw.lo printtree.lo printcsrc.lo relational.lo \ +symbol.lo utils.lo series.lo ncmul.lo clifford.lo structure.lo color.lo \ +indexed.lo idx.lo isospin.lo exprseq_suppl.lo lst.lo lst_suppl.lo \ +simp_lor.lo coloridx.lo lorentzidx.lo +CXXFLAGS = @CXXFLAGS@ +CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) +CXXLINK = $(LIBTOOL) --mode=link $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(ginacinclude_HEADERS) + +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP = --best +DEP_FILES = .deps/add.P .deps/basic.P .deps/clifford.P .deps/color.P \ +.deps/coloridx.P .deps/constant.P .deps/diff.P .deps/ex.P \ +.deps/expairseq.P .deps/exprseq.P .deps/exprseq_suppl.P .deps/fail.P \ +.deps/function.P .deps/idx.P .deps/indexed.P .deps/inifcns.P \ +.deps/inifcns_gamma.P .deps/inifcns_trans.P .deps/isospin.P \ +.deps/lorentzidx.P .deps/lst.P .deps/lst_suppl.P .deps/matrix.P \ +.deps/mul.P .deps/ncmul.P .deps/normal.P .deps/numeric.P \ +.deps/operators.P .deps/power.P .deps/print.P .deps/printcsrc.P \ +.deps/printraw.P .deps/printtree.P .deps/relational.P .deps/series.P \ +.deps/simp_lor.P .deps/structure.P .deps/symbol.P .deps/utils.P +CXXMKDEP = $(CXX) -M $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) +SOURCES = $(libginac_la_SOURCES) +OBJECTS = $(libginac_la_OBJECTS) + +all: Makefile $(LTLIBRARIES) $(HEADERS) + +.SUFFIXES: +.SUFFIXES: .S .c .cpp .lo .o .s +$(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu ginac/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-libLTLIBRARIES: + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + +distclean-libLTLIBRARIES: + +maintainer-clean-libLTLIBRARIES: + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libdir) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo "$(LIBTOOL) --mode=install $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p"; \ + $(LIBTOOL) --mode=install $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +libginac.la: $(libginac_la_OBJECTS) $(libginac_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libginac_la_LDFLAGS) $(libginac_la_OBJECTS) $(libginac_la_LIBADD) $(LIBS) +.cpp.o: + $(CXXCOMPILE) -c $< +.cpp.lo: + $(LTCXXCOMPILE) -c $< + +install-ginacincludeHEADERS: $(ginacinclude_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(ginacincludedir) + @list='$(ginacinclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ + echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(ginacincludedir)/$$p"; \ + $(INSTALL_DATA) $$d$$p $(DESTDIR)$(ginacincludedir)/$$p; \ + done + +uninstall-ginacincludeHEADERS: + @$(NORMAL_UNINSTALL) + list='$(ginacinclude_HEADERS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(ginacincludedir)/$$p; \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = ginac + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu ginac/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + +maintainer-clean-depend: + -rm -rf .deps + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).P -c $< + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).p -c $< + @-sed -e 's/^\([^:]*\)\.o:/\1.lo \1.o:/' \ + < .deps/$(*F).p > .deps/$(*F).P + @-rm -f .deps/$(*F).p + +%.o: %.cpp + @echo '$(CXXCOMPILE) -c $<'; \ + $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).P -c $< + +%.lo: %.cpp + @echo '$(LTCXXCOMPILE) -c $<'; \ + $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).p -c $< + @-sed -e 's/^\([^:]*\)\.o:/\1.lo \1.o:/' \ + < .deps/$(*F).p > .deps/$(*F).P + @-rm -f .deps/$(*F).p +info: +dvi: +check: all + $(MAKE) +installcheck: +install-exec: install-libLTLIBRARIES + @$(NORMAL_INSTALL) + +install-data: install-ginacincludeHEADERS + @$(NORMAL_INSTALL) + +install: install-exec install-data all + @: + +uninstall: uninstall-libLTLIBRARIES uninstall-ginacincludeHEADERS + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: + $(mkinstalldirs) $(DATADIR)$(libdir) $(DATADIR)$(ginacincludedir) + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-libLTLIBRARIES mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags mostlyclean-depend \ + mostlyclean-generic + +clean: clean-libLTLIBRARIES clean-compile clean-libtool clean-tags \ + clean-depend clean-generic mostlyclean + +distclean: distclean-libLTLIBRARIES distclean-compile distclean-libtool \ + distclean-tags distclean-depend distclean-generic clean + -rm -f config.status + -rm -f libtool + +maintainer-clean: maintainer-clean-libLTLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-depend \ + maintainer-clean-generic distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \ +clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \ +uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \ +distclean-compile clean-compile maintainer-clean-compile \ +mostlyclean-libtool distclean-libtool clean-libtool \ +maintainer-clean-libtool uninstall-ginacincludeHEADERS \ +install-ginacincludeHEADERS tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir mostlyclean-depend \ +distclean-depend clean-depend maintainer-clean-depend info dvi \ +installcheck install-exec install-data install uninstall all \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ginac/add.cpp b/ginac/add.cpp new file mode 100644 index 00000000..0d88e329 --- /dev/null +++ b/ginac/add.cpp @@ -0,0 +1,635 @@ +/** @file add.cpp + * + * Implementation of GiNaC's sums of expressions. */ + +#include +#include + +#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_degsetflag(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(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(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(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(mulref.duplicate()); + mul * mulcopyp=new mul(mulref); + mulcopyp->overall_coeff=exONE(); + mulcopyp->clearflag(status_flags::evaluated); + mulcopyp->clearflag(status_flags::hash_calculated); + if (are_ex_trivially_equal(c,exONE())) { + return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor); + } else if (are_ex_trivially_equal(numfactor,exONE())) { + return expair(mulcopyp->setflag(status_flags::dynallocated),c); + } + return expair(mulcopyp->setflag(status_flags::dynallocated), + ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c))); + } else if (is_ex_exactly_of_type(e,numeric)) { + if (are_ex_trivially_equal(c,exONE())) { + return expair(e,exONE()); + } + return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),exONE()); + } + return expair(e,c); +} + +expair add::combine_pair_with_coeff_to_pair(expair const & p, + ex const & c) const +{ + ASSERT(is_ex_exactly_of_type(p.coeff,numeric)); + ASSERT(is_ex_exactly_of_type(c,numeric)); + + if (is_ex_exactly_of_type(p.rest,numeric)) { + ASSERT(ex_to_numeric(p.coeff).is_equal(numONE())); // should be normalized + return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),exONE()); + } + + return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c))); +} + +ex add::recombine_pair_to_ex(expair const & p) const +{ + //if (p.coeff.compare(exONE())==0) { + //if (are_ex_trivially_equal(p.coeff,exONE())) { + if (ex_to_numeric(p.coeff).is_equal(numONE())) { + return p.rest; + } else { + return p.rest*p.coeff; + } +} + +ex add::expand(unsigned options) const +{ + epvector * vp=expandchildren(options); + if (vp==0) { + return *this; + } + return (new add(vp,overall_coeff))->setflag(status_flags::expanded | + status_flags::dynallocated ); +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +// none + +////////// +// static member variables +////////// + +// protected + +unsigned add::precedence=40; + +////////// +// global constants +////////// + +const add some_add; +type_info const & typeid_add=typeid(some_add); + + + diff --git a/ginac/add.h b/ginac/add.h new file mode 100644 index 00000000..6986b1e3 --- /dev/null +++ b/ginac/add.h @@ -0,0 +1,94 @@ +/** @file add.h + * + * Interface to GiNaC's sums of expressions. */ + +#ifndef _ADD_H_ +#define _ADD_H_ + +#include "expairseq.h" + +/** Sum of expressions. */ +class add : public expairseq +{ + friend class mul; + friend class ncmul; + friend class power; + +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers +public: + add(); + ~add(); + add(add const & other); + add const & operator=(add const & other); +protected: + void copy(add const & other); + void destroy(bool call_parent); + + // other constructors +public: + add(ex const & lh, ex const & rh); + add(exvector const & v); + add(epvector const & v); + //add(epvector const & v, bool do_not_canonicalize=0); + add(epvector const & v, ex const & oc); + add(epvector * vp, ex const & oc); + + // functions overriding virtual functions from bases classes +public: + basic * duplicate() const; + void printraw(ostream & os) const; + void print(ostream & os, unsigned upper_precedence=0) const; + void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const; + bool info(unsigned inf) const; + int degree(symbol const & s) const; + int ldegree(symbol const & s) const; + ex coeff(symbol const & s, int const n=1) const; + ex eval(int level=0) const; + ex diff(symbol const & s) const; + ex series(symbol const & s, ex const & point, int order) const; + ex normal(lst &sym_lst, lst &repl_lst, int level=0) const; + numeric integer_content(void) const; + ex smod(numeric const &xi) const; + numeric max_coefficient(void) const; + exvector get_indices(void) const; + ex simplify_ncmul(exvector const & v) const; +protected: + int compare_same_type(basic const & other) const; + bool is_equal_same_type(basic const & other) const; + unsigned return_type(void) const; + unsigned return_type_tinfo(void) const; + ex thisexpairseq(epvector const & v, ex const & oc) const; + ex thisexpairseq(epvector * vp, ex const & oc) const; + void printpair(ostream & os, expair const & p, + unsigned upper_precedence) const; + expair split_ex_to_pair(ex const & e) const; + expair combine_ex_with_coeff_to_pair(ex const & e, + ex const & c) const; + expair combine_pair_with_coeff_to_pair(expair const & p, + ex const & c) const; + ex recombine_pair_to_ex(expair const & p) const; + ex expand(unsigned options=0) const; + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class + // none + +// member variables + +protected: + static unsigned precedence; +}; + +// global constants + +extern const add some_add; +extern type_info const & typeid_add; + +#define ex_to_add(X) static_cast(*(X).bp) + +#endif // ndef _ADD_H_ + diff --git a/ginac/basic.cpp b/ginac/basic.cpp new file mode 100644 index 00000000..875bf758 --- /dev/null +++ b/ginac/basic.cpp @@ -0,0 +1,391 @@ +/** @file basic.cpp + * + * Implementation of GiNaC's ABC. */ + +#include +#include +#include + +#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(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(*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; ihold(); +} + +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(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; ihash_other) return 1; + + unsigned typeid_this = tinfo(); + unsigned typeid_other = other.tinfo(); + + if (typeid_thisprintraw(cout); + cout << " and "; + other.printraw(cout); + cout << endl; + */ + return -1; + } + if (typeid_this>typeid_other) { + /* + cout << "hash collision, different types: " + << *this << " and " << other << endl; + this->printraw(cout); + cout << " and "; + other.printraw(cout); + cout << endl; + */ + return 1; + } + + ASSERT(typeid(*this)==typeid(other)); + + int cmpval=compare_same_type(other); + if ((cmpval!=0)&&(hash_this<0x80000000U)) { + /* + cout << "hash collision, same type: " + << *this << " and " << other << endl; + this->printraw(cout); + cout << " and "; + other.printraw(cout); + cout << endl; + */ + } + return cmpval; +} + +bool basic::is_equal(basic const & other) const +{ + unsigned hash_this = gethash(); + unsigned hash_other = other.gethash(); + + if (hash_this!=hash_other) return false; + + unsigned typeid_this = tinfo(); + unsigned typeid_other = other.tinfo(); + + if (typeid_this!=typeid_other) return false; + + ASSERT(typeid(*this)==typeid(other)); + + return is_equal_same_type(other); +} + +// protected + +basic const & basic::hold(void) const +{ + return setflag(status_flags::evaluated); +} + +void basic::ensure_if_modifiable(void) const +{ + if (refcount>1) { + throw(std::runtime_error("cannot modify multiply referenced object")); + } +} + +////////// +// static member variables +////////// + +// protected + +unsigned basic::precedence=70; +unsigned basic::delta_indent=4; + +////////// +// global constants +////////// + +const basic some_basic; +type_info const & typeid_basic=typeid(some_basic); + +////////// +// global variables +////////// + +int max_recursion_level=1024; diff --git a/ginac/basic.h b/ginac/basic.h new file mode 100644 index 00000000..a0956171 --- /dev/null +++ b/ginac/basic.h @@ -0,0 +1,240 @@ +/** @file basic.h + * + * Interface to GiNaC's ABC. */ + +#ifndef _BASIC_H_ +#define _BASIC_H_ + +#include +#include +#include + +#include "flags.h" +#include "tinfos.h" +#include "debugmsg.h" + +class basic; +class ex; +class symbol; +class lst; +class numeric; + +typedef vector 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(const_cast(&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(const_cast(&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(const_cast((OBJ).bp))!=0) + +/* +#define is_ex_exactly_of_type(OBJ,TYPE) \ + (typeid(*(OBJ).bp)==typeid(some_##TYPE)) +*/ + +#define is_ex_exactly_of_type(OBJ,TYPE) \ + ((*(OBJ).bp).tinfo()==(some_##TYPE).tinfo()) + +#define are_ex_trivially_equal(EX1,EX2) \ + ((EX1).bp==(EX2).bp) + +// global functions + +inline unsigned rotate_left_31(unsigned n) +{ + // clear highest bit and shift 1 bit to the left + n=(n & 0x7FFFFFFFU) << 1; + + // overflow? clear highest bit and set lowest bit + if (n & 0x80000000U) { + n=(n & 0x7FFFFFFFU) | 0x00000001U; + } + + ASSERT(n<0x80000000U); + + return n; +} + +inline unsigned golden_ratio_hash(unsigned n) +{ +#if 0 + // This requires ´long long´ (or an equivalent 64 bit type)---which is, + // unfortunately, not ANSI-compliant: + unsigned long long l = n * 0x4f1bbcddLL; + return (l & 0x7fffffffU) ^ (l >> 32); +#else + // This requires ´long double´ to have a mantissa of at least 64 bit--- + // which is not guaranteed by any standard: + const static long double golden_ratio=.618033988749894848204586834370; + long double m=golden_ratio*n; + return unsigned((m-int(m))*0x80000000); +#endif +} + +#endif // ndef _BASIC_H_ diff --git a/ginac/clifford.cpp b/ginac/clifford.cpp new file mode 100644 index 00000000..98f3652d --- /dev/null +++ b/ginac/clifford.cpp @@ -0,0 +1,190 @@ +/** @file clifford.cpp + * + * Implementation of GiNaC's clifford objects. + * No real implementation yet, to be done. */ + +#include + +#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(&other); + if (serial==o->serial) { + return indexed::compare_same_type(other); + } + return serial < o->serial ? -1 : 1; +} + +ex clifford::simplify_ncmul(exvector const & v) const +{ + return simplified_ncmul(v); +} + +unsigned clifford::calchash(void) const +{ + hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555556U ^ + golden_ratio_hash(tinfo_key) ^ + serial)); + setflag(status_flags::hash_calculated); + return hashvalue; +} + +////////// +// virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +void clifford::setname(string const & n) +{ + name=n; +} + +// private + +string & clifford::autoname_prefix(void) +{ + static string * s=new string("clifford"); + return *s; +} + +////////// +// static member variables +////////// + +// private + +unsigned clifford::next_serial=0; + +////////// +// global constants +////////// + +const clifford some_clifford; +type_info const & typeid_clifford=typeid(some_clifford); + diff --git a/ginac/clifford.h b/ginac/clifford.h new file mode 100644 index 00000000..65ec005f --- /dev/null +++ b/ginac/clifford.h @@ -0,0 +1,75 @@ +/** @file clifford.h + * + * Interface to GiNaC's clifford objects. */ + +#ifndef _CLIFFORD_H_ +#define _CLIFFORD_H_ + +#include + +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(*(X).bp) + +#endif // ndef _CLIFFORD_H_ + + diff --git a/ginac/color.cpp b/ginac/color.cpp new file mode 100644 index 00000000..f790e941 --- /dev/null +++ b/ginac/color.cpp @@ -0,0 +1,953 @@ +/** @file color.cpp + * + * Implementation of GiNaC's color objects. + * No real implementation yet, to be done. */ + +#include +#include +#include +#include +#include + +#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_labelhold(); +} + +// protected + +int color::compare_same_type(basic const & other) const +{ + ASSERT(other.tinfo() == TINFO_COLOR); + const color *o = static_cast(&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(&other); + if (type!=o->type) return false; + if (representation_label!=o->representation_label) return false; + return indexed::is_equal_same_type(other); +} + +#include + +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 Tvecs; + Tvecs.resize(MAX_REPRESENTATION_LABELS); + vector 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=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 & Tvecs, + vector & 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 & Tvecs, + vector & ONEvecs, exvector & unknownvec) +{ + unsigned sz=delta8vec.size()+fvec.size()+dvec.size()+unknownvec.size(); + for (unsigned rl=0; rl Tvecs; + Tvecs.resize(MAX_REPRESENTATION_LABELS); + vector 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=2) { + for (unsigned i=0; i counter; + counter.resize(iv_double.size()); + int l; + for (l=0; unsigned(l)=0)&&((++counter[l])>COLOR_EIGHT)) { + counter[l]=1; + l--; + } + if (l<2) { cout << counter[0] << counter[1] << endl; } + if (l<0) break; + } + + return sum; +} + +void append_exvector_to_exvector(exvector & dest, exvector const & source) +{ + for (exvector::const_iterator cit=source.begin(); cit!=source.end(); ++cit) { + dest.push_back(*cit); + } +} + + + + + + + + + + + + + diff --git a/ginac/color.h b/ginac/color.h new file mode 100644 index 00000000..3237359e --- /dev/null +++ b/ginac/color.h @@ -0,0 +1,143 @@ +/** @file color.h + * + * Interface to GiNaC's color objects. */ + +#ifndef _COLOR_H_ +#define _COLOR_H_ + +#include +#include + +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 & Tvecs, + vector & ONEvecs, + exvector & unknownvec); + friend exvector recombine_color_string(exvector & delta8vec, exvector & fvec, + exvector & dvec, vector & Tvecs, + vector & 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(*(X).bp) +#define ex_to_nonconst_color(X) static_cast(*(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 & Tvecs, + vector & ONEvecs, + exvector & unknownvec); +exvector recombine_color_string(exvector & delta8vec, exvector & fvec, + exvector & dvec, vector & Tvecs, + vector & ONEvecs, exvector & unknownvec); +ex color_trace_of_one_representation_label(exvector const & v); +ex color_trace(exvector const & v, unsigned const rl=0); +ex simplify_pure_color_string(ex const & e); +ex simplify_color(ex const & e); + +ex brute_force_sum_color_indices(ex const & e); + +void append_exvector_to_exvector(exvector & dest, exvector const & source); + +#endif // ndef _COLOR_H_ + + diff --git a/ginac/coloridx.cpp b/ginac/coloridx.cpp new file mode 100644 index 00000000..2b12a997 --- /dev/null +++ b/ginac/coloridx.cpp @@ -0,0 +1,196 @@ +/** @file coloridx.cpp + * + * Implementation of GiNaC's color indices. */ + +#include + +#include "ginac.h" +#include "utils.h" + +////////// +// default constructor, destructor, copy constructor assignment operator and helpers +////////// + +// public + +coloridx::coloridx() +{ + debugmsg("coloridx default constructor",LOGLEVEL_CONSTRUCT); + // serial is incremented in idx::idx() + name="color"+ToString(serial); + tinfo_key=TINFO_COLORIDX; +} + +coloridx::~coloridx() +{ + debugmsg("coloridx destructor",LOGLEVEL_DESTRUCT); + destroy(0); +} + +coloridx::coloridx(coloridx const & other) +{ + debugmsg("coloridx copy constructor",LOGLEVEL_CONSTRUCT); + copy(other); +} + +coloridx const & coloridx::operator=(coloridx const & other) +{ + debugmsg("coloridx operator=",LOGLEVEL_ASSIGNMENT); + if (this != &other) { + destroy(1); + copy(other); + } + return *this; +} + +// protected + +void coloridx::copy(coloridx const & other) +{ + idx::copy(other); +} + +void coloridx::destroy(bool call_parent) +{ + if (call_parent) idx::destroy(call_parent); +} + +////////// +// other constructors +////////// + +// public + +coloridx::coloridx(bool cov) : idx(cov) +{ + debugmsg("coloridx constructor from bool",LOGLEVEL_CONSTRUCT); + // serial is incremented in idx::idx(bool) + name="color"+ToString(serial); + tinfo_key=TINFO_COLORIDX; +} + +coloridx::coloridx(string const & n, bool cov) : idx(n,cov) +{ + debugmsg("coloridx constructor from string,bool",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_COLORIDX; +} + +coloridx::coloridx(char const * n, bool cov) : idx(n,cov) +{ + debugmsg("coloridx constructor from char*,bool",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_COLORIDX; +} + +coloridx::coloridx(unsigned const v, bool cov) : idx(v,cov) +{ + debugmsg("coloridx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_COLORIDX; +} + +////////// +// functions overriding virtual functions from bases classes +////////// + +// public + +basic * coloridx::duplicate() const +{ + debugmsg("coloridx duplicate",LOGLEVEL_DUPLICATE); + return new coloridx(*this); +} + +void coloridx::printraw(ostream & os) const +{ + debugmsg("coloridx printraw",LOGLEVEL_PRINT); + + os << "coloridx("; + + if (symbolic) { + os << "symbolic,name=" << name; + } else { + os << "non symbolic,value=" << value; + } + + if (covariant) { + os << ",covariant"; + } else { + os << ",contravariant"; + } + + os << ",serial=" << serial; + os << ",hash=" << hashvalue << ",flags=" << flags; + os << ")"; +} + +void coloridx::printtree(ostream & os, unsigned indent) const +{ + debugmsg("coloridx printtree",LOGLEVEL_PRINT); + + os << string(indent,' ') << "coloridx: "; + + if (symbolic) { + os << "symbolic,name=" << name; + } else { + os << "non symbolic,value=" << value; + } + + if (covariant) { + os << ",covariant"; + } else { + os << ",contravariant"; + } + + os << ", serial=" << serial + << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")" + << ", flags=" << flags << endl; +} + +void coloridx::print(ostream & os, unsigned upper_precedence) const +{ + debugmsg("coloridx print",LOGLEVEL_PRINT); + + if (covariant) { + os << "_"; + } else { + os << "~"; + } + if (symbolic) { + os << name; + } else { + os << value; + } +} + +bool coloridx::info(unsigned inf) const +{ + if (inf==info_flags::coloridx) return true; + return idx::info(inf); +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +// none + +////////// +// static member variables +////////// + +// none + +////////// +// global constants +////////// + +const coloridx some_coloridx; +type_info const & typeid_coloridx=typeid(some_coloridx); + + + diff --git a/ginac/coloridx.h b/ginac/coloridx.h new file mode 100644 index 00000000..92e6b1ff --- /dev/null +++ b/ginac/coloridx.h @@ -0,0 +1,63 @@ +/** @file coloridx.h + * + * Interface to GiNaC's color indices. */ + +#ifndef _COLORIDX_H_ +#define _COLORIDX_H_ + +#include +#include + +#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(*(X).bp)) + +#endif // ndef _COLORIDX_H_ diff --git a/ginac/constant.cpp b/ginac/constant.cpp new file mode 100644 index 00000000..a1cc1ef9 --- /dev/null +++ b/ginac/constant.cpp @@ -0,0 +1,143 @@ +/** @file constant.cpp + * + * Implementation of GiNaC's constant types and some special constants. */ + +#include +#include + +#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(const_cast(other)); + // return name.compare(o.name); + const constant *o = static_cast(&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(&other); + return serial==o->serial; +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +// none + +////////// +// static member variables +////////// + +unsigned constant::next_serial=0; + +////////// +// global constants +////////// + +const constant some_constant("",0); +type_info const & typeid_constant=typeid(some_constant); + +/** Pi. (3.14159...) Diverts straight into CLN for evalf(). */ +const constant Pi("Pi", PiEvalf); +/** Catalan's constant. (0.91597...) Diverts straight into CLN for evalf(). */ +const constant EulerGamma("EulerGamma", EulerGammaEvalf); +/** Euler's constant. (0.57721...) Sometimes called Euler-Mascheroni constant. + * Diverts straight into CLN for evalf(). */ +const constant Catalan("Catalan", CatalanEvalf); diff --git a/ginac/constant.h b/ginac/constant.h new file mode 100644 index 00000000..ef7e8c8d --- /dev/null +++ b/ginac/constant.h @@ -0,0 +1,77 @@ +/** @file constant.h + * + * Interface to GiNaC's constant types and some special constants. */ + +#ifndef _CONSTANT_H_ +#define _CONSTANT_H_ + +#include + +class constant; + +#include "ex.h" +#include "numeric.h" + +/** This class holds constants, symbols with specific numerical value. Each + * object of this class must either provide their own function to evaluate it + * to class numeric or provide the constant as a numeric (if it's an exact + * number). */ +class constant : public basic +{ + +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers +public: + ~constant(); + constant(constant const & other); + // constant const & operator=(constant const & other); /* it's pervert! */ +protected: + void copy(constant const & other); + void destroy(bool call_parent); + + // other constructors +public: + constant(string const & initname, ex (*efun)()=0); + constant(string const & initname, numeric const & initnumber); + + // functions overriding virtual functions from bases classes +public: + basic * duplicate() const; + void printraw(ostream & os) const; + void print(ostream & os, unsigned upper_precedence=0) const; + void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const; + ex evalf(int level=0) const; + ex diff(symbol const & s) const; +protected: + int compare_same_type(basic const & other) const; + bool is_equal_same_type(basic const & other) const; + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class + // none + +// member variables + +private: + string name; + ex (*ef)(); + numeric * number; + bool fct_assigned; + unsigned serial; //!< unique serial number for comparision + static unsigned next_serial; +}; + +// global constants + +extern const constant some_constant; +extern type_info const & typeid_constant; + +// extern const numeric I; +extern const constant Pi; +extern const constant Catalan; +extern const constant EulerGamma; + +#endif // ndef _CONSTANT_H_ diff --git a/ginac/container.pl b/ginac/container.pl new file mode 100755 index 00000000..d7b860bc --- /dev/null +++ b/ginac/container.pl @@ -0,0 +1,816 @@ +#!/usr/bin/perl -w + +if ($#ARGV!=0) { + die 'usage: container.pl type (type=lst or exprseq)'; +} + +if ($ARGV[0] eq 'lst') { + $type='lst'; +} elsif ($ARGV[0] eq 'exprseq') { + $type='exprseq'; +} else { + die 'only lst and exprseq supported'; +} + +#$type='lst'; +#$type='exprseq'; + +if ($type eq 'exprseq') { + + # settings for exprseq + $CONTAINER="exprseq"; + $STLHEADER="vector"; + $reserve=1; + $prepend=0; + $let_op=0; + $open_bracket='('; + $close_bracket=')'; + +} elsif ($type eq 'lst') { + + # settings for lst + $CONTAINER="lst"; + $STLHEADER="list"; + $reserve=0; + $prepend=1; + $let_op=1; + $open_bracket='['; + $close_bracket=']'; + +} else { + die "invalid type $type"; +} + +$CONTAINER_UC=uc(${CONTAINER}); +$STLT="ex".$STLHEADER; + +if ($reserve) { + $RESERVE_IMPLEMENTATION="#define RESERVE(s,size) (s).reserve(size)"; +} else { + $RESERVE_IMPLEMENTATION="#define RESERVE(s,size) // no reserve needed for ${STLHEADER}"; +} + +if ($prepend) { + $PREPEND_INTERFACE=<=0); + ASSERT(i + +#include + +typedef ${STLHEADER} ${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=< +#include + +#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(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(other)); + if (seq.size()!=o.seq.size()) return false; + + ${STLT}::const_iterator it1=seq.begin(); + ${STLT}::const_iterator it2=o.seq.begin(); + + for (; it1!=seq.end(); ++it1, ++it2) { + if (!(*it1).is_equal(*it2)) return false; + } + + return true; +} + +unsigned ${CONTAINER}::return_type(void) const +{ + return return_types::noncommutative_composite; +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// public + +${CONTAINER} & ${CONTAINER}::append(ex const & b) +{ + ensure_if_modifiable(); + seq.push_back(b); + return *this; +} + +${PREPEND_IMPLEMENTATION} + +// protected + +void ${CONTAINER}::printseq(ostream & os, char openbracket, char delim, + char closebracket, unsigned this_precedence, + unsigned upper_precedence) const +{ + if (this_precedence<=upper_precedence) os << openbracket; + if (seq.size()!=0) { + ${STLT}::const_iterator it,it_last; + it=seq.begin(); + it_last=seq.end(); + --it_last; + for (; it!=it_last; ++it) { + (*it).bp->print(os,this_precedence); + os << delim; + } + (*it).bp->print(os,this_precedence); + } + if (this_precedence<=upper_precedence) os << closebracket; +} + +ex ${CONTAINER}::this${CONTAINER}(${STLT} const & v) const +{ + return ${CONTAINER}(v); +} + +ex ${CONTAINER}::this${CONTAINER}(${STLT} * vp) const +{ + return ${CONTAINER}(vp); +} + +////////// +// non-virtual functions in this class +////////// + +// public + +// none + +// protected + +bool ${CONTAINER}::is_canonical() const +{ + if (seq.size()<=1) { return 1; } + + ${STLT}::const_iterator it=seq.begin(); + ${STLT}::const_iterator it_last=it; + for (++it; it!=seq.end(); it_last=it, ++it) { + if ((*it_last).compare(*it)>0) { + if ((*it_last).compare(*it)>0) { + cout << *it_last << ">" << *it << "\\n"; + return 0; + } + } + } + return 1; +} + + +${STLT} ${CONTAINER}::evalchildren(int level) const +{ + ${STLT} s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).eval(level)); + } + return s; +} + +${STLT} ${CONTAINER}::evalfchildren(int level) const +{ + ${STLT} s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).evalf(level)); + } + return s; +} + +${STLT} ${CONTAINER}::normalchildren(int level) const +{ + ${STLT} s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).normal(level)); + } + return s; +} + +${STLT} ${CONTAINER}::diffchildren(symbol const & y) const +{ + ${STLT} s; + RESERVE(s,seq.size()); + for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).diff(y)); + } + return s; +} + +/* obsolete subschildren +${STLT} ${CONTAINER}::subschildren(lst const & ls, lst const & lr) const +{ + ${STLT} s; + RESERVE(s,seq.size()); + for (${STLT}::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).subs(ls,lr)); + } + return s; +} +*/ + +${STLT} * ${CONTAINER}::subschildren(lst const & ls, lst const & lr) const +{ + // returns a NULL pointer if nothing had to be substituted + // returns a pointer to a newly created epvector otherwise + // (which has to be deleted somewhere else) + + ${STLT}::const_iterator last=seq.end(); + ${STLT}::const_iterator cit=seq.begin(); + while (cit!=last) { + ex const & subsed_ex=(*cit).subs(ls,lr); + if (!are_ex_trivially_equal(*cit,subsed_ex)) { + + // something changed, copy seq, subs and return it + ${STLT} *s=new ${STLT}; + RESERVE(*s,seq.size()); + + // copy parts of seq which are known not to have changed + ${STLT}::const_iterator cit2=seq.begin(); + while (cit2!=cit) { + s->push_back(*cit2); + ++cit2; + } + // copy first changed element + s->push_back(subsed_ex); + ++cit2; + // copy rest + while (cit2!=last) { + s->push_back((*cit2).subs(ls,lr)); + ++cit2; + } + return s; + } + ++cit; + } + + return 0; // nothing has changed +} + +////////// +// static member variables +////////// + +// protected + +unsigned ${CONTAINER}::precedence=10; + +////////// +// global constants +////////// + +const ${CONTAINER} some_${CONTAINER}; +type_info const & typeid_${CONTAINER}=typeid(some_${CONTAINER}); + +END_OF_IMPLEMENTATION + +print "Creating interface file ${CONTAINER}.h..."; +open OUT,">${CONTAINER}.h" or die "cannot open ${CONTAINER}.h"; +print OUT $interface; +close OUT; +print "ok.\n"; + +print "Creating implementation file ${CONTAINER}.cpp..."; +open OUT,">${CONTAINER}.cpp" or die "cannot open ${CONTAINER}.cpp"; +print OUT $implementation; +close OUT; +print "ok.\n"; + +print "done.\n"; diff --git a/ginac/debugmsg.h b/ginac/debugmsg.h new file mode 100644 index 00000000..caf8bcb4 --- /dev/null +++ b/ginac/debugmsg.h @@ -0,0 +1,42 @@ +/** @file debugmsg.h + * + * Utilities needed for debugging only. */ + +#ifndef _DEBUGMSG_H_ +#define _DEBUGMSG_H_ + +#ifdef _DEBUG +#define VERBOSE +#define DOASSERT (VERBOSE||DEBUG) +#endif + +#define LOGLEVEL_CONSTRUCT 0x0001 +#define LOGLEVEL_DESTRUCT 0x0002 +#define LOGLEVEL_ASSIGNMENT 0x0004 +#define LOGLEVEL_DUPLICATE 0x0008 +#define LOGLEVEL_PRINT 0x0010 +#define LOGLEVEL_OPERATOR 0x0020 +#define LOGLEVEL_MEMBER_FUNCTION 0x4000 +#define LOGLEVEL_NONMEMBER_FUNCTION 0x8000 +#define LOGLEVEL_ALL 0xffff + +#define LOGMASK (LOGLEVEL_PRINT) +// #define LOGMASK (LOGLEVEL_PRINT | LOGLEVEL_ASSIGNMENT | LOGLEVEL_OPERATOR | LOGLEVEL_DUPLICATE | LOGLEVEL_OPERATOR | LOGLEVEL_MEMBER_FUNCTION | LOGLEVEL_NONMEMBER_FUNCTION ) + +#include +#include + +#ifdef VERBOSE +#define debugmsg(msg, loglevel) if ((loglevel) & ~LOGMASK) clog << (msg) << endl; +#else +#define debugmsg(msg, loglevel) +#endif // def VERBOSE + +#ifdef DOASSERT +#define ASSERT(X) assert(X) +#else +#define ASSERT(X) ((void)0) +#endif + +#endif // ndef _DEBUGMSG_H_ + diff --git a/ginac/diff.cpp b/ginac/diff.cpp new file mode 100644 index 00000000..b8ef4c5c --- /dev/null +++ b/ginac/diff.cpp @@ -0,0 +1,208 @@ +/** @file diff.cpp + * + * Implementation of symbolic differentiation in all of GiNaC's classes. */ + +#include + +#include "ginac.h" + +/** Default implementation of ex::diff(). It prints and error message and returns a fail object. + * @see ex::diff */ +ex basic::diff(symbol const & s) const +{ + throw(std::logic_error("differentiation not supported by this type")); +} + + +/** Implementation of ex::diff() for a numeric. It always returns 0. + * + * @see ex::diff */ +ex numeric::diff(symbol const & s) const +{ + return exZERO(); +} + + +/** Implementation of ex::diff() for single differentiation of a symbol. + * It returns 1 or 0. + * + * @see ex::diff */ +ex symbol::diff(symbol const & s) const +{ + if (compare_same_type(s)) { + return exZERO(); + } else { + return exONE(); + } +} + +/** Implementation of ex::diff() for a constant. It always returns 0. + * + * @see ex::diff */ +ex constant::diff(symbol const & s) const +{ + return exZERO(); +} + +/** Implementation of ex::diff() for multiple differentiation of a symbol. + * It returns the symbol, 1 or 0. + * + * @param nth order of differentiation + * @see ex::diff */ +ex symbol::diff(symbol const & s, unsigned nth) const +{ + if (compare_same_type(s)) { + switch (nth) { + case 0: + return s; + break; + case 1: + return exONE(); + break; + default: + return exZERO(); + } + } else { + return exONE(); + } +} + + +/** Implementation of ex::diff() for an indexed object. It always returns 0. + * @see ex::diff */ +ex indexed::diff(symbol const & s) const +{ + return exZERO(); +} + + +/** Implementation of ex::diff() for an expairseq. It differentiates all elements of the sequence. + * @see ex::diff */ +ex expairseq::diff(symbol const & s) const +{ + return thisexpairseq(diffchildren(s),overall_coeff); +} + + +/** Implementation of ex::diff() for a sum. It differentiates each term. + * @see ex::diff */ +ex add::diff(symbol const & s) const +{ + // D(a+b+c)=D(a)+D(b)+D(c) + return (new add(diffchildren(s)))->setflag(status_flags::dynallocated); +} + + +/** Implementation of ex::diff() for a product. It applies the product rule. + * @see ex::diff */ +ex mul::diff(symbol const & s) const +{ + exvector new_seq; + new_seq.reserve(seq.size()); + + // D(a*b*c)=D(a)*b*c+a*D(b)*c+a*b*D(c) + for (unsigned i=0; i!=seq.size(); i++) { + epvector sub_seq=seq; + sub_seq[i] = split_ex_to_pair(sub_seq[i].coeff* + power(sub_seq[i].rest,sub_seq[i].coeff-1)* + sub_seq[i].rest.diff(s)); + new_seq.push_back((new mul(sub_seq,overall_coeff))->setflag(status_flags::dynallocated)); + } + return (new add(new_seq))->setflag(status_flags::dynallocated); +} + + +/** Implementation of ex::diff() for a non-commutative product. It always returns 0. + * @see ex::diff */ +ex ncmul::diff(symbol const & s) const +{ + return exZERO(); +} + + +/** Implementation of ex::diff() for a power. + * @see ex::diff */ +ex power::diff(symbol const & s) const +{ + if (exponent.info(info_flags::real)) { + // D(b^r) = r * b^(r-1) * D(b) (faster than the formula below) + return mul(mul(exponent, power(basis, exponent - exONE())), basis.diff(s)); + } else { + // D(b^e) = b^e * (D(e)*ln(b) + e*D(b)/b) + return mul(power(basis, exponent), + add(mul(exponent.diff(s), log(basis)), + mul(mul(exponent, basis.diff(s)), power(basis, -1)))); + } +} + + +/** Implementation of ex::diff() for functions. It applies the chain rule, + * except for the Order term function. + * @see ex::diff */ +ex function::diff(symbol const & s) const +{ + exvector new_seq; + + if (serial == function_index_Order) { + + // Order Term function only differentiates the argument + return Order(seq[0].diff(s)); + + } else { + + // Chain rule + for (unsigned i=0; i!=seq.size(); i++) { + new_seq.push_back(mul(pdiff(i), seq[i].diff(s))); + } + } + return add(new_seq); +} + + +/** Implementation of ex::diff() for a power-series. It treats the series as a polynomial. + * @see ex::diff */ +ex series::diff(symbol const & s) const +{ + if (s == var) { + epvector new_seq; + epvector::const_iterator it = seq.begin(), itend = seq.end(); + + //!! coeff might depend on var + while (it != itend) { + if (is_order_function(it->rest)) { + new_seq.push_back(expair(it->rest, it->coeff - 1)); + } else { + ex c = it->rest * it->coeff; + if (!c.is_zero()) + new_seq.push_back(expair(c, it->coeff - 1)); + } + it++; + } + return series(var, point, new_seq); + } else { + return *this; + } +} + + +/** Compute partial derivative of an expression. + * + * @param s symbol by which the expression is derived + * @param nth order of derivative (default 1) + * @return partial derivative as a new expression */ + +ex ex::diff(symbol const & s, unsigned nth) const +{ + ASSERT(bp!=0); + + if ( nth==0 ) { + return *this; + } + + ex ndiff = bp->diff(s); + while ( nth>1 ) { + ndiff = ndiff.diff(s); + --nth; + } + return ndiff; +} diff --git a/ginac/ex.cpp b/ginac/ex.cpp new file mode 100644 index 00000000..7cb0c6f6 --- /dev/null +++ b/ginac/ex.cpp @@ -0,0 +1,490 @@ +/** @file ex.cpp + * + * Implementation of GiNaC's light-weight expression handles. */ + +#include + +#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; iinfo(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; icollect(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(other); + } + } else { + if (other.flags & status_flags::dynallocated) { + bp=&const_cast(other); + } else { + bp=other.duplicate(); + bp->setflag(status_flags::dynallocated); + } + ASSERT(bp!=0); + // bp->clearflag(status_flags::evaluated); + ++bp->refcount; + } + ASSERT(bp!=0); + ASSERT(bp->flags & status_flags::dynallocated); +} + +////////// +// static member variables +////////// + +// none + +////////// +// functions which are not member functions +////////// + +// none + +////////// +// global functions +////////// + +ex const & exZERO(void) +{ + static ex * eZERO=new ex(numZERO()); + return *eZERO; +} + +ex const & exONE(void) +{ + static ex * eONE=new ex(numONE()); + return *eONE; +} + +ex const & exTWO(void) +{ + static ex * eTWO=new ex(numTWO()); + return *eTWO; +} + +ex const & exTHREE(void) +{ + static ex * eTHREE=new ex(numTHREE()); + return *eTHREE; +} + +ex const & exMINUSONE(void) +{ + static ex * eMINUSONE=new ex(numMINUSONE()); + return *eMINUSONE; +} + +ex const & exHALF(void) +{ + static ex * eHALF=new ex(ex(1)/ex(2)); + return *eHALF; +} + +ex const & exMINUSHALF(void) +{ + static ex * eMINUSHALF=new ex(numeric(-1,2)); + return *eMINUSHALF; +} + diff --git a/ginac/ex.h b/ginac/ex.h new file mode 100644 index 00000000..2300627e --- /dev/null +++ b/ginac/ex.h @@ -0,0 +1,269 @@ +/** @file ex.h + * + * Interface to GiNaC's light-weight expression handles. */ + +#ifndef _EX_H_ +#define _EX_H_ + +#include + +class ex; +class expand_options; +class status_flags; + +#include "basic.h" +#include "debugmsg.h" +#include "flags.h" + +class symbol; +class lst; + +typedef vector exvector; + +// enum definitions + +ex const & exZERO(void); +ex const & exONE(void); +ex const & exTWO(void); +ex const & exTHREE(void); +ex const & exMINUSONE(void); +ex const & exHALF(void); +ex const & exMINUSHALF(void); + +#define INLINE_EX_CONSTRUCTORS + +/** Lightweight interface to GiNaC's symbolic objects. Basically all it does is + * to hold a pointer to the other objects, manage the reference counting and + * provide methods for manipulation of these objects. */ +class ex +{ + friend class basic; + +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers +public: + ex() +#ifdef INLINE_EX_CONSTRUCTORS + : bp(exZERO().bp) + { + debugmsg("ex default constructor",LOGLEVEL_CONSTRUCT); + ASSERT(exZERO().bp!=0); + ASSERT(exZERO().bp->flags & status_flags::dynallocated); + ASSERT(bp!=0); + ++bp->refcount; + } +#else +; +#endif // def INLINE_EX_CONSTRUCTORS + + ~ex() +#ifdef INLINE_EX_CONSTRUCTORS + { + debugmsg("ex destructor",LOGLEVEL_DESTRUCT); + ASSERT(bp!=0); + ASSERT(bp->flags & status_flags::dynallocated); + if (--bp->refcount == 0) { + delete bp; + } + } +#else +; +#endif // def INLINE_EX_CONSTRUCTORS + + ex(ex const & other) +#ifdef INLINE_EX_CONSTRUCTORS + : bp(other.bp) + { + debugmsg("ex copy constructor",LOGLEVEL_CONSTRUCT); + ASSERT(bp!=0); + ASSERT((bp->flags) & status_flags::dynallocated); + ++bp->refcount; + } +#else +; +#endif // def INLINE_EX_CONSTRUCTORS + + ex const & operator=(ex const & other) +#ifdef INLINE_EX_CONSTRUCTORS + { + debugmsg("ex operator=",LOGLEVEL_ASSIGNMENT); + ASSERT(bp!=0); + ASSERT(bp->flags & status_flags::dynallocated); + ASSERT(other.bp!=0); + ASSERT(other.bp->flags & status_flags::dynallocated); + ++other.bp->refcount; + basic * tmpbp=other.bp; + if (--bp->refcount==0) { + delete bp; + } + bp=tmpbp; + return *this; + } +#else +; +#endif // def INLINE_EX_CONSTRUCTORS + + // other constructors +public: + ex(basic const & other) +#ifdef INLINE_EX_CONSTRUCTORS + { + debugmsg("ex constructor from basic",LOGLEVEL_CONSTRUCT); + construct_from_basic(other); + } +#else +; +#endif // def INLINE_EX_CONSTRUCTORS + + ex(int const i); + ex(unsigned int const i); + ex(long const i); + ex(unsigned long const i); + ex(double const d); + + // functions overriding virtual functions from bases classes + // none + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class +public: + void swap(ex & other); + void printraw(ostream & os) const; + void printtree(ostream & os, unsigned indent=0) const; + void print(ostream & os, unsigned upper_precedence=0) const; + void printcsrc(ostream & os, unsigned type, const char *var_name) const; + void dbgprint(void) const; + void dbgprinttree(void) const; + bool info(unsigned inf) const; + int nops() const; + ex expand(unsigned options=0) const; + bool has(ex const & other) const; + int degree(symbol const & s) const; + int ldegree(symbol const & s) const; + ex coeff(symbol const & s, int const n=1) const; + ex lcoeff(symbol const & s) const { return coeff(s, degree(s)); } + ex tcoeff(symbol const & s) const { return coeff(s, ldegree(s)); } + ex numer(bool normalize = true) const; + ex denom(bool normalize = true) const; + ex unit(const symbol &x) const; + ex content(const symbol &x) const; + numeric integer_content(void) const; + ex primpart(const symbol &x) const; + ex primpart(const symbol &x, const ex &cont) const; + ex normal(int level = 0) const; + ex smod(const numeric &xi) const; + numeric max_coefficient(void) const; + ex collect(symbol const & s) const; + ex eval(int level = 0) const; + ex evalf(int level = 0) const; + ex diff(symbol const & s, unsigned nth = 1) const; + ex series(symbol const & s, ex const & point, int order = 6) const; + ex subs(lst const & ls, lst const & lr) const; + ex subs(ex const & e) const; + exvector get_indices(void) const; + ex simplify_ncmul(exvector const & v) const; + ex operator[](ex const & index) const; + ex operator[](int const i) const; + ex op(int const i) const; + ex & let_op(int const i); + int compare(ex const & other) const +#ifdef INLINE_EX_CONSTRUCTORS + { + ASSERT(bp!=0); + ASSERT(other.bp!=0); + if (bp==other.bp) { + // special case: both expression point to same basic, trivially equal + return 0; + } + return bp->compare(*other.bp); + } +#else +; +#endif // def INLINE_EX_CONSTRUCTORS + bool is_equal(ex const & other) const +#ifdef INLINE_EX_CONSTRUCTORS + { + ASSERT(bp!=0); + ASSERT(other.bp!=0); + if (bp==other.bp) { + // special case: both expression point to same basic, trivially equal + return true; + } + return bp->is_equal(*other.bp); + } +#else +; +#endif // def INLINE_EX_CONSTRUCTORS + bool is_zero(void) const {return compare(exZERO()) == 0;}; + + unsigned return_type(void) const; + unsigned return_type_tinfo(void) const; + unsigned gethash(void) const; + + ex exadd(ex const & rh) const; + ex exmul(ex const & rh) const; + ex exncmul(ex const & rh) const; +private: + void construct_from_basic(basic const & other); + void makewriteable(); + +// member variables + +public: + basic *bp; + +}; + +// wrapper functions around member functions +inline int nops(ex const & thisex) +{ return thisex.nops(); } + +inline ex expand(ex const & thisex, unsigned options = 0) +{ return thisex.expand(options); } + +inline bool has(ex const & thisex, ex const & other) +{ return thisex.has(other); } + +inline int degree(ex const & thisex, symbol const & s) +{ return thisex.degree(s); } + +inline int ldegree(ex const & thisex, symbol const & s) +{ return thisex.ldegree(s); } + +inline ex coeff(ex const & thisex, symbol const & s, int const n=1) +{ return thisex.coeff(s, n); } + +inline ex numer(ex const & thisex, bool normalize = true) +{ return thisex.numer(normalize); } + +inline ex denom(ex const & thisex, bool normalize = true) +{ return thisex.denom(normalize); } + +inline ex normal(ex const & thisex, int level=0) +{ return thisex.normal(level); } + +inline ex collect(ex const & thisex, symbol const & s) +{ return thisex.collect(s); } + +inline ex eval(ex const & thisex, int level = 0) +{ return thisex.eval(level); } + +inline ex evalf(ex const & thisex, int level = 0) +{ return thisex.evalf(level); } + +inline ex diff(ex const & thisex, symbol const & s, unsigned nth = 1) +{ return thisex.diff(s, nth); } + +inline ex subs(ex const & thisex, ex const & e) +{ return thisex.subs(e); } + +inline ex subs(ex const & thisex, lst const & ls, lst const & lr) +{ return thisex.subs(ls, lr); } + +inline void swap(ex & e1, ex & e2) +{ e1.swap(e2); } + +#endif // ndef _EX_H_ diff --git a/ginac/expair.h b/ginac/expair.h new file mode 100644 index 00000000..ffe95322 --- /dev/null +++ b/ginac/expair.h @@ -0,0 +1,173 @@ +/** @file expair.h */ + +/** A pair of expressions. + * This similar to, but slightly extended STL's pair<> but we need to account + * for methods like .compare() */ +class expair +{ +public: + expair() {} + ~expair() {} + expair(expair const & other) : rest(other.rest), coeff(other.coeff) + { + ASSERT(is_ex_exactly_of_type(coeff,numeric)); + } + expair const & operator=(expair const & other) + { + if (this != &other) { + rest=other.rest; + coeff=other.coeff; + } + return *this; + } + expair(ex const & r, ex const & c) : rest(r), coeff(c) + { + ASSERT(is_ex_exactly_of_type(coeff,numeric)); + } + + bool is_numeric_with_coeff_1(void) const + { + ASSERT(is_ex_exactly_of_type(coeff,numeric)); + return is_ex_exactly_of_type(rest,numeric) && + (ex_to_numeric(coeff).compare(numONE())==0); + } + + bool is_equal(expair const & other) const + { + return (rest.is_equal(other.rest) && coeff.is_equal(other.coeff)); + } + bool is_less(expair const & other) const + { + return (rest.compare(other.rest)<0) || + (!(other.rest.compare(rest)<0) && (coeff.compare(other.coeff)<0)); + } + int compare(expair const & other) const + { + int cmpval=rest.compare(other.rest); + if (cmpval!=0) return cmpval; + cmpval=coeff.compare(other.coeff); + return cmpval; + } + + bool is_less_old2(expair const & other) const + { + /* + bool this_numeric_with_coeff_1=is_numeric_with_coeff_1(); + bool other_numeric_with_coeff_1=other.is_numeric_with_coeff_1(); + if (this_numeric_with_coeff_1) { + if (other_numeric_with_coeff_1) { + // both have coeff 1: compare rests + return rest.compare(other.rest)<0; + } + // only this has coeff 1: > + return false; + } else if (other_numeric_with_coeff_1) { + // only other has coeff 1: < + return true; + } + return (rest.compare(other.rest)<0) || + (!(other.rest.compare(rest)<0) && + (coeff.compare(other.coeff)<0)); + */ + if (is_ex_exactly_of_type(rest,numeric) && + is_ex_exactly_of_type(other.rest,numeric)) { + if (ex_to_numeric(coeff).compare(numONE())==0) { + if (ex_to_numeric(other.coeff).compare(numONE())==0) { + // both have coeff 1: compare rests + return rest.compare(other.rest)<0; + } + // only this has coeff 1: > + return false; + } else if (ex_to_numeric(other.coeff).compare(numONE())==0) { + // only other has coeff 1: < + return true; + } + // neither has coeff 1: usual compare + } + return (rest.compare(other.rest)<0) || + (!(other.rest.compare(rest)<0) && + (coeff.compare(other.coeff)<0)); + } + int compare_old2(expair const & other) const + { + if (is_ex_exactly_of_type(rest,numeric) && + is_ex_exactly_of_type(other.rest,numeric)) { + if (ex_to_numeric(coeff).compare(numONE())==0) { + if (ex_to_numeric(other.coeff).compare(numONE())==0) { + // both have coeff 1: compare rests + return rest.compare(other.rest); + } + // only this has coeff 1: > + return 1; + } else if (ex_to_numeric(other.coeff).compare(numONE())==0) { + // only other has coeff 1: < + return -1; + } + // neither has coeff 1: usual compare + } + /* + bool this_numeric_with_coeff_1=is_numeric_with_coeff_1(); + bool other_numeric_with_coeff_1=other.is_numeric_with_coeff_1(); + if (this_numeric_with_coeff_1) { + if (other_numeric_with_coeff_1) { + // both have coeff 1: compare rests + return rest.compare(other.rest); + } + // only this has coeff 1: > + return 1; + } else if (other_numeric_with_coeff_1) { + // only other has coeff 1: < + return -1; + // neither has coeff 1: usual compare + } + */ + int cmpval=rest.compare(other.rest); + if (cmpval!=0) return cmpval; + return coeff.compare(other.coeff); + } + bool is_less_old(expair const & other) const + { + return (rest.compare(other.rest)<0) || + (!(other.rest.compare(rest)<0) && (coeff.compare(other.coeff)<0)); + } + int compare_old(expair const & other) const + { + int cmpval=rest.compare(other.rest); + if (cmpval!=0) return cmpval; + cmpval=coeff.compare(other.coeff); + return cmpval; + } + + void printraw(ostream & os) const + { + os << "expair("; + rest.printraw(os); + os << ","; + coeff.printraw(os); + os << ")"; + } + + ex rest; + ex coeff; +}; + +class expair_is_less +{ +public: + bool operator()(expair const & lh, expair const & rh) const + { + return lh.is_less(rh); + } +}; + +class expair_is_less_old +{ +public: + bool operator()(expair const & lh, expair const & rh) const + { + return lh.is_less_old(rh); + } +}; + + + diff --git a/ginac/expairseq.cpp b/ginac/expairseq.cpp new file mode 100644 index 00000000..96811383 --- /dev/null +++ b/ginac/expairseq.cpp @@ -0,0 +1,1604 @@ +/** @file expairseq.cpp */ + +#include +#include +#include + +#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; ihold(); + } + + 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(const_cast(other)); + + int cmpval; + + // compare number of elements + if (seq.size() != o.seq.size()) { + return (seq.size()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(const_cast(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; i0) { + 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 + +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=0); + ASSERT((hashindex & 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 & 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 touched; + touched.reserve(seq.size()); + for (unsigned i=0; i0) return 1; // not canoncalized +#endif // def EXPAIRSEQ_USE_HASHTAB + + epvector::const_iterator it=seq.begin(); + epvector::const_iterator it_last=it; + for (++it; it!=seq.end(); it_last=it, ++it) { + if (!((*it_last).is_less(*it)||(*it_last).is_equal(*it))) { + if (!is_ex_exactly_of_type((*it_last).rest,numeric)|| + !is_ex_exactly_of_type((*it).rest,numeric)) { + // double test makes it easier to set a breakpoint... + if (!is_ex_exactly_of_type((*it_last).rest,numeric)|| + !is_ex_exactly_of_type((*it).rest,numeric)) { + printpair(cout,*it_last,0); + cout << ">"; + printpair(cout,*it,0); + cout << "\n"; + cout << "pair1:" << endl; + (*it_last).rest.printtree(cout); + (*it_last).coeff.printtree(cout); + cout << "pair2:" << endl; + (*it).rest.printtree(cout); + (*it).coeff.printtree(cout); + return 0; + } + } + } + } + return 1; +} + +epvector * expairseq::expandchildren(unsigned options) const +{ + epvector::const_iterator last=seq.end(); + epvector::const_iterator cit=seq.begin(); + while (cit!=last) { + ex const & expanded_ex=(*cit).rest.expand(options); + if (!are_ex_trivially_equal((*cit).rest,expanded_ex)) { + + // something changed, copy seq, eval and return it + epvector *s=new epvector; + s->reserve(seq.size()); + + // copy parts of seq which are known not to have changed + epvector::const_iterator cit2=seq.begin(); + while (cit2!=cit) { + s->push_back(*cit2); + ++cit2; + } + // copy first changed element + s->push_back(combine_ex_with_coeff_to_pair(expanded_ex, + (*cit2).coeff)); + ++cit2; + // copy rest + while (cit2!=last) { + s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.expand(options), + (*cit2).coeff)); + ++cit2; + } + return s; + } + ++cit; + } + + return 0; // nothing has changed +} + +epvector * expairseq::evalchildren(int level) const +{ + // returns a NULL pointer if nothing had to be evaluated + // returns a pointer to a newly created epvector otherwise + // (which has to be deleted somewhere else) + + if (level==1) { + return 0; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + + --level; + epvector::const_iterator last=seq.end(); + epvector::const_iterator cit=seq.begin(); + while (cit!=last) { + ex const & evaled_ex=(*cit).rest.eval(level); + if (!are_ex_trivially_equal((*cit).rest,evaled_ex)) { + + // something changed, copy seq, eval and return it + epvector *s=new epvector; + s->reserve(seq.size()); + + // copy parts of seq which are known not to have changed + epvector::const_iterator cit2=seq.begin(); + while (cit2!=cit) { + s->push_back(*cit2); + ++cit2; + } + // copy first changed element + s->push_back(combine_ex_with_coeff_to_pair(evaled_ex, + (*cit2).coeff)); + ++cit2; + // copy rest + while (cit2!=last) { + s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.eval(level), + (*cit2).coeff)); + ++cit2; + } + return s; + } + ++cit; + } + + return 0; // nothing has changed +} + +epvector expairseq::evalfchildren(int level) const +{ + epvector s; + s.reserve(seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back(combine_ex_with_coeff_to_pair((*it).rest.evalf(level), + (*it).coeff)); + } + return s; +} + +epvector expairseq::normalchildren(int level) const +{ + epvector s; + s.reserve(seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back(combine_ex_with_coeff_to_pair((*it).rest.normal(level), + (*it).coeff)); + } + return s; +} + +epvector expairseq::diffchildren(symbol const & y) const +{ + epvector s; + s.reserve(seq.size()); + + for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back(combine_ex_with_coeff_to_pair((*it).rest.diff(y), + (*it).coeff)); + } + return s; +} + +epvector * expairseq::subschildren(lst const & ls, lst const & lr) const +{ + // returns a NULL pointer if nothing had to be substituted + // returns a pointer to a newly created epvector otherwise + // (which has to be deleted somewhere else) + + epvector::const_iterator last=seq.end(); + epvector::const_iterator cit=seq.begin(); + while (cit!=last) { + ex const & subsed_ex=(*cit).rest.subs(ls,lr); + if (!are_ex_trivially_equal((*cit).rest,subsed_ex)) { + + // something changed, copy seq, subs and return it + epvector *s=new epvector; + s->reserve(seq.size()); + + // copy parts of seq which are known not to have changed + epvector::const_iterator cit2=seq.begin(); + while (cit2!=cit) { + s->push_back(*cit2); + ++cit2; + } + // copy first changed element + s->push_back(combine_ex_with_coeff_to_pair(subsed_ex, + (*cit2).coeff)); + ++cit2; + // copy rest + while (cit2!=last) { + s->push_back(combine_ex_with_coeff_to_pair((*cit2).rest.subs(ls,lr), + (*cit2).coeff)); + ++cit2; + } + return s; + } + ++cit; + } + + return 0; // nothing has changed +} + +/* +epvector expairseq::subschildren(lst const & ls, lst const & lr) const +{ + epvector s; + s.reserve(seq.size()); + + for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back(split_ex_to_pair((*it).rest.subs(ls,lr),(*it).coeff)); + } + return s; +} +*/ + +/* +void expairseq::sort(epviter first, epviter last, expair_is_less comp) +{ + if (first != last) { + introsort_loop(first, last, lg(last - first) * 2, comp); + __final_insertion_sort(first, last, comp); + } +} + +ptrdiff_t expairseq::lg(ptrdiff_t n) +{ + ptrdiff_t k; + for (k = 0; n > 1; n >>= 1) ++k; + return k; +} + +void expairseq::introsort_loop(epviter first, epviter last, + ptrdiff_t depth_limit, expair_is_less comp) +{ + while (last - first > stl_threshold) { + if (depth_limit == 0) { + partial_sort(first, last, last, comp); + return; + } + --depth_limit; + epviter cut = unguarded_partition(first, last, + expair(__median(*first, *(first + (last - first)/2), + *(last - 1), comp)), comp); + introsort_loop(cut, last, depth_limit, comp); + last = cut; + } +} + +epviter expairseq::unguarded_partition(epviter first, epviter last, + expair pivot, expair_is_less comp) +{ + while (1) { + while (comp(*first, pivot)) ++first; + --last; + while (comp(pivot, *last)) --last; + if (!(first < last)) return first; + iter_swap(first, last); + ++first; + } +} + +void expairseq::partial_sort(epviter first, epviter middle, epviter last, + expair_is_less comp) { + make_heap(first, middle, comp); + for (RandomAccessIterator i = middle; i < last; ++i) + if (comp(*i, *first)) + __pop_heap(first, middle, i, T(*i), comp, distance_type(first)); + sort_heap(first, middle, comp); +} +*/ + +////////// +// static member variables +////////// + +// protected + +unsigned expairseq::precedence=10; + +#ifdef EXPAIRSEQ_USE_HASHTAB +unsigned expairseq::maxhashtabsize=0x4000000U; +unsigned expairseq::minhashtabsize=0x1000U; +unsigned expairseq::hashtabfactor=1; +#endif // def EXPAIRSEQ_USE_HASHTAB + +////////// +// global constants +////////// + +const expairseq some_expairseq; +type_info const & typeid_expairseq=typeid(some_expairseq); + diff --git a/ginac/expairseq.h b/ginac/expairseq.h new file mode 100644 index 00000000..e6511e8e --- /dev/null +++ b/ginac/expairseq.h @@ -0,0 +1,183 @@ +/** @file expairseq.h */ + +#ifndef _EXPAIRSEQ_H_ +#define _EXPAIRSEQ_H_ + +#include +#include + +class expairseq; + +#include "basic.h" +#include "ex.h" +#include "numeric.h" +#include "debugmsg.h" +#include "expair.h" + +//#define EXPAIRSEQ_USE_HASHTAB + +typedef vector 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 epplist; +typedef vector 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 & touched, + unsigned & number_of_zeroes); + void drop_coeff_0_terms(epvector::iterator & first_numeric, + epvector::iterator & last_non_zero, + vector & 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(*(X).bp) + +#endif // ndef _EXPAIRSEQ_H_ + + diff --git a/ginac/exprseq.cpp b/ginac/exprseq.cpp new file mode 100644 index 00000000..9e566c34 --- /dev/null +++ b/ginac/exprseq.cpp @@ -0,0 +1,594 @@ +/** @file exprseq.cpp + * + * Implementation of GiNaC's exprseq. + * This file was generated automatically by container.pl. + * Please do not modify it directly, edit the perl script instead! + * container.pl options: $CONTAINER=exprseq + * $STLHEADER=vector + * $reserve=1 + * $prepend=0 + * $let_op=0 + * $open_bracket=( + * $close_bracket=) */ + +#include +#include + +#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(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 + (const_cast(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 + (const_cast(other)); + if (seq.size()!=o.seq.size()) return false; + + exvector::const_iterator it1=seq.begin(); + exvector::const_iterator it2=o.seq.begin(); + + for (; it1!=seq.end(); ++it1, ++it2) { + if (!(*it1).is_equal(*it2)) return false; + } + + return true; +} + +unsigned exprseq::return_type(void) const +{ + return return_types::noncommutative_composite; +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// public + +exprseq & exprseq::append(ex const & b) +{ + ensure_if_modifiable(); + seq.push_back(b); + return *this; +} + + + +// protected + +void exprseq::printseq(ostream & os, char openbracket, char delim, + char closebracket, unsigned this_precedence, + unsigned upper_precedence) const +{ + if (this_precedence<=upper_precedence) os << openbracket; + if (seq.size()!=0) { + exvector::const_iterator it,it_last; + it=seq.begin(); + it_last=seq.end(); + --it_last; + for (; it!=it_last; ++it) { + (*it).bp->print(os,this_precedence); + os << delim; + } + (*it).bp->print(os,this_precedence); + } + if (this_precedence<=upper_precedence) os << closebracket; +} + +ex exprseq::thisexprseq(exvector const & v) const +{ + return exprseq(v); +} + +ex exprseq::thisexprseq(exvector * vp) const +{ + return exprseq(vp); +} + +////////// +// non-virtual functions in this class +////////// + +// public + +// none + +// protected + +bool exprseq::is_canonical() const +{ + if (seq.size()<=1) { return 1; } + + exvector::const_iterator it=seq.begin(); + exvector::const_iterator it_last=it; + for (++it; it!=seq.end(); it_last=it, ++it) { + if ((*it_last).compare(*it)>0) { + if ((*it_last).compare(*it)>0) { + cout << *it_last << ">" << *it << "\n"; + return 0; + } + } + } + return 1; +} + + +exvector exprseq::evalchildren(int level) const +{ + exvector s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).eval(level)); + } + return s; +} + +exvector exprseq::evalfchildren(int level) const +{ + exvector s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).evalf(level)); + } + return s; +} + +exvector exprseq::normalchildren(int level) const +{ + exvector s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).normal(level)); + } + return s; +} + +exvector exprseq::diffchildren(symbol const & y) const +{ + exvector s; + RESERVE(s,seq.size()); + for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).diff(y)); + } + return s; +} + +/* obsolete subschildren +exvector exprseq::subschildren(lst const & ls, lst const & lr) const +{ + exvector s; + RESERVE(s,seq.size()); + for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).subs(ls,lr)); + } + return s; +} +*/ + +exvector * exprseq::subschildren(lst const & ls, lst const & lr) const +{ + // returns a NULL pointer if nothing had to be substituted + // returns a pointer to a newly created epvector otherwise + // (which has to be deleted somewhere else) + + exvector::const_iterator last=seq.end(); + exvector::const_iterator cit=seq.begin(); + while (cit!=last) { + ex const & subsed_ex=(*cit).subs(ls,lr); + if (!are_ex_trivially_equal(*cit,subsed_ex)) { + + // something changed, copy seq, subs and return it + exvector *s=new exvector; + RESERVE(*s,seq.size()); + + // copy parts of seq which are known not to have changed + exvector::const_iterator cit2=seq.begin(); + while (cit2!=cit) { + s->push_back(*cit2); + ++cit2; + } + // copy first changed element + s->push_back(subsed_ex); + ++cit2; + // copy rest + while (cit2!=last) { + s->push_back((*cit2).subs(ls,lr)); + ++cit2; + } + return s; + } + ++cit; + } + + return 0; // nothing has changed +} + +////////// +// static member variables +////////// + +// protected + +unsigned exprseq::precedence=10; + +////////// +// global constants +////////// + +const exprseq some_exprseq; +type_info const & typeid_exprseq=typeid(some_exprseq); + diff --git a/ginac/exprseq.h b/ginac/exprseq.h new file mode 100644 index 00000000..aeb8a2dd --- /dev/null +++ b/ginac/exprseq.h @@ -0,0 +1,115 @@ +/** @file exprseq.h + * + * Definition of GiNaC's exprseq. + * This file was generated automatically by container.pl. + * Please do not modify it directly, edit the perl script instead! + * container.pl options: $CONTAINER=exprseq + * $STLHEADER=vector + * $reserve=1 + * $prepend=0 + * $let_op=0 + * $open_bracket=( + * $close_bracket=) */ + +#ifndef _EXPRSEQ_H_ +#define _EXPRSEQ_H_ + +#include + +#include + +typedef vector 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(*(X).bp)) + +#endif // ndef _EXPRSEQ_H_ + diff --git a/ginac/exprseq_suppl.cpp b/ginac/exprseq_suppl.cpp new file mode 100644 index 00000000..22b35ec0 --- /dev/null +++ b/ginac/exprseq_suppl.cpp @@ -0,0 +1,21 @@ +/** @file exprseq_suppl.cpp + * + * Supplement to exprseq.cpp, contains the parts which were + * not automatically generated. */ + +#include "ginac.h" + +bool exprseq::info(unsigned inf) const +{ + if (inf==info_flags::exprseq) return 1; + return basic::info(inf); +} + +ex & exprseq::let_op(int const i) +{ + ASSERT(i>=0); + ASSERT(i +#include + +#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(serialprint(os); + } + os << ")"; +} + +void function::print(ostream & os, unsigned upper_precedence) const +{ + debugmsg("function print",LOGLEVEL_PRINT); + + ASSERT(serialbp->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(const_cast(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(const_cast(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 & function::registered_functions(void) +{ + static vector * rf=new vector; + return *rf; +} + +// public + +// the following lines have been generated for max. 10 parameters +unsigned function::register_new(char const * nm, eval_funcp_1 e, + evalf_funcp_1 ef, diff_funcp_1 d, series_funcp_1 s) +{ + registered_function_info rfi={nm,1,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_2 e, + evalf_funcp_2 ef, diff_funcp_2 d, series_funcp_2 s) +{ + registered_function_info rfi={nm,2,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_3 e, + evalf_funcp_3 ef, diff_funcp_3 d, series_funcp_3 s) +{ + registered_function_info rfi={nm,3,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_4 e, + evalf_funcp_4 ef, diff_funcp_4 d, series_funcp_4 s) +{ + registered_function_info rfi={nm,4,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_5 e, + evalf_funcp_5 ef, diff_funcp_5 d, series_funcp_5 s) +{ + registered_function_info rfi={nm,5,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_6 e, + evalf_funcp_6 ef, diff_funcp_6 d, series_funcp_6 s) +{ + registered_function_info rfi={nm,6,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_7 e, + evalf_funcp_7 ef, diff_funcp_7 d, series_funcp_7 s) +{ + registered_function_info rfi={nm,7,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_8 e, + evalf_funcp_8 ef, diff_funcp_8 d, series_funcp_8 s) +{ + registered_function_info rfi={nm,8,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_9 e, + evalf_funcp_9 ef, diff_funcp_9 d, series_funcp_9 s) +{ + registered_function_info rfi={nm,9,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +unsigned function::register_new(char const * nm, eval_funcp_10 e, + evalf_funcp_10 ef, diff_funcp_10 d, series_funcp_10 s) +{ + registered_function_info rfi={nm,10,0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} + +// end of generated lines + +////////// +// static member variables +////////// + +// none + +////////// +// global constants +////////// + +const function some_function; +type_info const & typeid_function=typeid(some_function); + diff --git a/ginac/function.h b/ginac/function.h new file mode 100644 index 00000000..312b12df --- /dev/null +++ b/ginac/function.h @@ -0,0 +1,276 @@ +/** @file function.h + * + * Interface to abstract class function (new function concept). + * + * This file was generated automatically by function.pl. + * Please do not modify it directly, edit the perl script instead! + * function.pl options: $maxargs=10 */ + +#ifndef _FUNCTION_H_ +#define _FUNCTION_H_ + +#include +#include +#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_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(OBJ.bp)->getserial() == function_index_##FUNCNAME) + +// global constants + +extern const function some_function; +extern type_info const & typeid_function; + +#endif // ndef _FUNCTION_H_ + diff --git a/ginac/function.pl b/ginac/function.pl new file mode 100755 index 00000000..6ebdada4 --- /dev/null +++ b/ginac/function.pl @@ -0,0 +1,613 @@ +#!/usr/bin/perl -w + +$maxargs=10; + +sub generate_seq { + my ($seq_template,$n)=@_; + my ($res,$N); + + $res=''; + for ($N=1; $N<=$n; $N++) { + $res .= eval('"' . $seq_template . '"'); + if ($N!=$n) { + $res .= ', '; + } + } + return $res; +} + +sub generate { + my ($template,$seq_template1,$seq_template2)=@_; + my ($res,$N,$SEQ); + + $res=''; + for ($N=1; $N<=$maxargs; $N++) { + $SEQ1=generate_seq($seq_template1,$N); + $SEQ2=generate_seq($seq_template2,$N); + $res .= eval('"' . $template . '"'); + $SEQ1=''; # to avoid main::SEQ1 used only once warning + $SEQ2=''; # same as above + } + return $res; +} + +$declare_function_macro=generate( + <<'END_OF_DECLARE_FUNCTION_MACRO','ex const & p${N}','p${N}'); +#define DECLARE_FUNCTION_${N}P(NAME) \\ +extern unsigned function_index_##NAME; \\ +inline function NAME(${SEQ1}) { \\ + return function(function_index_##NAME, ${SEQ2}); \\ +} + +END_OF_DECLARE_FUNCTION_MACRO + +$typedef_eval_funcp=generate( +'typedef ex (* eval_funcp_${N})(${SEQ1});'."\n", +'ex const &',''); + +$typedef_evalf_funcp=generate( +'typedef ex (* evalf_funcp_${N})(${SEQ1});'."\n", +'ex const &',''); + +$typedef_diff_funcp=generate( +'typedef ex (* diff_funcp_${N})(${SEQ1}, unsigned);'."\n", +'ex const &',''); + +$typedef_series_funcp=generate( +'typedef ex (* series_funcp_${N})(${SEQ1}, symbol const &, ex const &, int);'."\n", +'ex const &',''); + +$constructors_interface=generate( +' function(unsigned ser, ${SEQ1});'."\n", +'ex const & param${N}',''); + +$register_new_interface=generate( +' static unsigned register_new(char const * nm, eval_funcp_${N} e,'."\n". +' evalf_funcp_${N} ef=0, diff_funcp_${N} d=0, series_funcp_${N} s=0);'. +"\n",'',''); + +$constructors_implementation=generate( + <<'END_OF_CONSTRUCTORS_IMPLEMENTATION','ex const & param${N}','param${N}'); +function::function(unsigned ser, ${SEQ1}) + : exprseq(${SEQ2}), serial(ser) +{ + debugmsg(\"function constructor from unsigned,${N}*ex\",LOGLEVEL_CONSTRUCT); + tinfo_key = TINFO_FUNCTION; +} +END_OF_CONSTRUCTORS_IMPLEMENTATION + +$eval_switch_statement=generate( + <<'END_OF_EVAL_SWITCH_STATEMENT','eseq[${N}-1]',''); + case ${N}: + return ((eval_funcp_${N})(registered_functions()[serial].e))(${SEQ1}); + break; +END_OF_EVAL_SWITCH_STATEMENT + +$evalf_switch_statement=generate( + <<'END_OF_EVALF_SWITCH_STATEMENT','eseq[${N}-1]',''); + case ${N}: + return ((evalf_funcp_${N})(registered_functions()[serial].ef))(${SEQ1}); + break; +END_OF_EVALF_SWITCH_STATEMENT + +$diff_switch_statement=generate( + <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]',''); + case ${N}: + return ((diff_funcp_${N})(registered_functions()[serial].d))(${SEQ1},diff_param); + break; +END_OF_DIFF_SWITCH_STATEMENT + +$series_switch_statement=generate( + <<'END_OF_SERIES_SWITCH_STATEMENT','seq[${N}-1]',''); + case ${N}: + return ((series_funcp_${N})(registered_functions()[serial].s))(${SEQ1},s,point,order); + break; +END_OF_SERIES_SWITCH_STATEMENT + +$register_new_implementation=generate( + <<'END_OF_REGISTER_NEW_IMPLEMENTATION','',''); +unsigned function::register_new(char const * nm, eval_funcp_${N} e, + evalf_funcp_${N} ef, diff_funcp_${N} d, series_funcp_${N} s) +{ + registered_function_info rfi={nm,${N},0,eval_funcp(e), + evalf_funcp(ef),diff_funcp(d),series_funcp(s)}; + registered_functions().push_back(rfi); + return registered_functions().size()-1; +} +END_OF_REGISTER_NEW_IMPLEMENTATION + +$interface=< +#include +#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_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(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=< +#include + +#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(serialprint(os); + } + os << ")"; +} + +void function::print(ostream & os, unsigned upper_precedence) const +{ + debugmsg("function print",LOGLEVEL_PRINT); + + ASSERT(serialbp->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(const_cast(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(const_cast(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 & function::registered_functions(void) +{ + static vector * rf=new vector; + return *rf; +} + +// public + +// the following lines have been generated for max. ${maxargs} parameters +$register_new_implementation +// end of generated lines + +////////// +// static member variables +////////// + +// none + +////////// +// global constants +////////// + +const function some_function; +type_info const & typeid_function=typeid(some_function); + +END_OF_IMPLEMENTATION + +print "Creating interface file function.h..."; +open OUT,">function.h" or die "cannot open function.h"; +print OUT $interface; +close OUT; +print "ok.\n"; + +print "Creating implementation file function.cpp..."; +open OUT,">function.cpp" or die "cannot open function.cpp"; +print OUT $implementation; +close OUT; +print "ok.\n"; + +print "done.\n"; diff --git a/ginac/ginac.h b/ginac/ginac.h new file mode 100644 index 00000000..1892097e --- /dev/null +++ b/ginac/ginac.h @@ -0,0 +1,36 @@ +/* ginac.h */ + +#ifndef __GINAC_H__ +#define __GINAC_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef GINAC_BASE_ONLY +#include +#include +#include +#include +#include +#include +#endif /* ndef GINAC_BASE_ONLY */ + +#endif /* ndef __GINAC_H__ */ diff --git a/ginac/idx.cpp b/ginac/idx.cpp new file mode 100644 index 00000000..9829b876 --- /dev/null +++ b/ginac/idx.cpp @@ -0,0 +1,427 @@ +/** @file idx.cpp + * + * Implementation of GiNaC's indices. */ + +#include + +#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 + (const_cast(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 + (const_cast(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 + (const_cast(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(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 +#include + +#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(*(X).bp)) + +// other functions + +typedef vector exvector; + +int canonicalize_indices(exvector & iv, bool antisymmetric=false); +exvector idx_intersect(exvector const & iv1, exvector const & iv2); +ex permute_free_index_to_front(exvector const & iv3, exvector const & iv2, + bool antisymmetric, int * sig); +unsigned subs_index_in_exvector(exvector & v, ex const & is, ex const & ir); +ex subs_indices(ex const & e, exvector const & idxv_contra, + exvector const & idxv_co); +unsigned count_index(ex const & e, ex const & i); + +#endif // ndef _IDX_H_ diff --git a/ginac/indexed.cpp b/ginac/indexed.cpp new file mode 100644 index 00000000..2d6419d6 --- /dev/null +++ b/ginac/indexed.cpp @@ -0,0 +1,271 @@ +/** @file indexed.cpp + * + * Implementation of GiNaC's index carrying objects. */ + +#include + +#include "ginac.h" + +////////// +// default constructor, destructor, copy constructor assignment operator and helpers +////////// + +// public + +indexed::indexed() +{ + debugmsg("indexed default constructor",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_INDEXED; +} + +indexed::~indexed() +{ + debugmsg("indexed destructor",LOGLEVEL_DESTRUCT); + destroy(0); +} + +indexed::indexed(indexed const & other) +{ + debugmsg("indexed copy constructor",LOGLEVEL_CONSTRUCT); + copy (other); +} + +indexed const & indexed::operator=(indexed const & other) +{ + debugmsg("indexed operator=",LOGLEVEL_ASSIGNMENT); + if (this != &other) { + destroy(1); + copy(other); + } + return *this; +} + +// protected + +void indexed::copy(indexed const & other) +{ + exprseq::copy(other); +} + +void indexed::destroy(bool call_parent) +{ + if (call_parent) { + exprseq::destroy(call_parent); + } +} + +////////// +// other constructors +////////// + +// public + +indexed::indexed(ex const & i1) : exprseq(i1) +{ + debugmsg("indexed constructor from ex",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_INDEXED; + ASSERT(all_of_type_idx()); +} + +indexed::indexed(ex const & i1, ex const & i2) : exprseq(i1,i2) +{ + debugmsg("indexed constructor from ex,ex",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_INDEXED; + ASSERT(all_of_type_idx()); +} + +indexed::indexed(ex const & i1, ex const & i2, ex const & i3) + : exprseq(i1,i2,i3) +{ + debugmsg("indexed constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_INDEXED; + ASSERT(all_of_type_idx()); +} + +indexed::indexed(exvector const & iv) : exprseq(iv) +{ + debugmsg("indexed constructor from exvector",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_INDEXED; + ASSERT(all_of_type_idx()); +} + +indexed::indexed(exvector * ivp) : exprseq(ivp) +{ + debugmsg("indexed constructor from exvector *",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_INDEXED; + ASSERT(all_of_type_idx()); +} + +////////// +// functions overriding virtual functions from bases classes +////////// + +// public + +basic * indexed::duplicate() const +{ + debugmsg("indexed duplicate",LOGLEVEL_DUPLICATE); + return new indexed(*this); +} + +void indexed::printraw(ostream & os) const +{ + debugmsg("indexed printraw",LOGLEVEL_PRINT); + os << "indexed(indices="; + printrawindices(os); + os << ",hash=" << hashvalue << ",flags=" << flags << ")"; +} + +void indexed::printtree(ostream & os, unsigned indent) const +{ + debugmsg("indexed printtree",LOGLEVEL_PRINT); + os << string(indent,' ') << "indexed: " << seq.size() << " indices"; + os << ",hash=" << hashvalue << ",flags=" << flags << endl; + printtreeindices(os,indent); +} + +void indexed::print(ostream & os, unsigned upper_precedence) const +{ + debugmsg("indexed print",LOGLEVEL_PRINT); + os << "UNNAMEDINDEX"; + printindices(os); +} + +void indexed::printcsrc(ostream & os, unsigned type, + unsigned upper_precedence) const +{ + debugmsg("indexed print csrc",LOGLEVEL_PRINT); + print(os,upper_precedence); +} + +bool indexed::info(unsigned inf) const +{ + if (inf==info_flags::indexed) return true; + if (inf==info_flags::has_indices) return seq.size()!=0; + return exprseq::info(inf); +} + +exvector indexed::get_indices(void) const +{ + return seq; + + /* + idxvector filtered_indices; + filtered_indices.reserve(indices.size()); + for (idxvector::const_iterator cit=indices.begin(); cit!=indices.end(); ++cit) { + if ((*cit).get_type()==t) { + filtered_indices.push_back(*cit); + } + } + return filtered_indices; + */ +} + +// protected + +int indexed::compare_same_type(basic const & other) const +{ + ASSERT(is_of_type(other,indexed)); + return exprseq::compare_same_type(other); +} + +bool indexed::is_equal_same_type(basic const & other) const +{ + ASSERT(is_of_type(other,indexed)); + return exprseq::is_equal_same_type(other); +} + +unsigned indexed::return_type(void) const +{ + return return_types::noncommutative; +} + +unsigned indexed::return_type_tinfo(void) const +{ + return tinfo_key; +} + +ex indexed::thisexprseq(exvector const & v) const +{ + return indexed(v); +} + +ex indexed::thisexprseq(exvector * vp) const +{ + return indexed(vp); +} + +////////// +// virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +// protected + +void indexed::printrawindices(ostream & os) const +{ + if (seq.size()!=0) { + for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) { + (*cit).printraw(os); + os << ","; + } + } +} + +void indexed::printtreeindices(ostream & os, unsigned indent) const +{ + if (seq.size()!=0) { + for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) { + os << string(indent+delta_indent,' '); + (*cit).printraw(os); + os << endl; + } + } +} + +void indexed::printindices(ostream & os) const +{ + if (seq.size()!=0) { + if (seq.size()>1) { + os << "{"; + } + exvector::const_iterator last=seq.end()-1; + exvector::const_iterator cit=seq.begin(); + for (; cit!=last; ++cit) { + (*cit).print(os); + os << ","; + } + (*cit).print(os); + if (seq.size()>1) { + os << "}"; + } + } +} + +bool indexed::all_of_type_idx(void) const +{ + // used only inside of ASSERTs + for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) { + if (!is_ex_of_type(*cit,idx)) return false; + } + return true; +} + +////////// +// static member variables +////////// + +// none + +////////// +// global constants +////////// + +const indexed some_indexed; +type_info const & typeid_indexed=typeid(some_indexed); + diff --git a/ginac/indexed.h b/ginac/indexed.h new file mode 100644 index 00000000..4bade0b2 --- /dev/null +++ b/ginac/indexed.h @@ -0,0 +1,81 @@ +/** @file indexed.h + * + * Interface to GiNaC's index carrying objects. */ + +#ifndef _INDEXED_H_ +#define _INDEXED_H_ + +#include + +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(*(X).bp) + +#endif // ndef _INDEXED_H_ + + diff --git a/ginac/inifcns.cpp b/ginac/inifcns.cpp new file mode 100644 index 00000000..adf31860 --- /dev/null +++ b/ginac/inifcns.cpp @@ -0,0 +1,218 @@ +/** @file inifcns.cpp + * + * Implementation of GiNaC's initially known functions. */ + +#include +#include + +#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(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 +#include + +#include "ginac.h" + +////////// +// gamma function +////////// + +/** Evaluation of gamma(x). Knows about integer arguments, half-integer + * arguments and that's it. Somebody ought to provide some good numerical + * evaluation some day... + * + * @exception fail_numeric("complex_infinity") or something similar... */ +ex gamma_eval(ex const & x) +{ + if ( x.info(info_flags::numeric) ) { + + // trap integer arguments: + if ( x.info(info_flags::integer) ) { + // gamma(n+1) -> n! for postitive n + if ( x.info(info_flags::posint) ) { + return factorial(ex_to_numeric(x).sub(numONE())); + } else { + return numZERO(); // Infinity. Throw? What? + } + } + // trap half integer arguments: + if ( (x*2).info(info_flags::integer) ) { + // trap positive x=(n+1/2) + // gamma(n+1/2) -> Pi^(1/2)*(1*3*..*(2*n-1))/(2^n) + if ( (x*2).info(info_flags::posint) ) { + numeric n = ex_to_numeric(x).sub(numHALF()); + numeric coefficient = doublefactorial(n.mul(numTWO()).sub(numONE())); + coefficient = coefficient.div(numTWO().power(n)); + return mul(coefficient,power(Pi,numHALF())); + } else { + // trap negative x=(-n+1/2) + // gamma(-n+1/2) -> Pi^(1/2)*(-2)^n/(1*3*..*(2*n-1)) + numeric n = abs(ex_to_numeric(x).sub(numHALF())); + numeric coefficient = numeric(-2).power(n); + coefficient = coefficient.div(doublefactorial(n.mul(numTWO()).sub(numONE())));; + return mul(coefficient,power(Pi,numHALF())); + } + } + } + return gamma(x).hold(); +} + +ex gamma_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(gamma(x)) + + return gamma(ex_to_numeric(x)); +} + +ex gamma_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return power(x, -1); //!! +} + +ex gamma_series(ex const & x, symbol const & s, ex const & point, int order) +{ + //!! Only handle one special case for now... + if (x.is_equal(s) && point.is_zero()) { + ex e = 1 / s - EulerGamma + s * (power(Pi, 2) / 12 + power(EulerGamma, 2) / 2) + Order(power(s, 2)); + return e.series(s, point, order); + } else + throw(std::logic_error("don't know the series expansion of this particular gamma function")); +} + +REGISTER_FUNCTION(gamma, gamma_eval, gamma_evalf, gamma_diff, gamma_series); diff --git a/ginac/inifcns_trans.cpp b/ginac/inifcns_trans.cpp new file mode 100644 index 00000000..c67d8330 --- /dev/null +++ b/ginac/inifcns_trans.cpp @@ -0,0 +1,717 @@ +/** @file inifcns_trans.cpp + * + * Implementation of transcendental (and trigonometric and hyperbolic) + * functions. */ + +#include +#include + +#include "ginac.h" + +////////// +// exponential function +////////// + +ex exp_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(exp(x)) + + return exp(ex_to_numeric(x)); // -> numeric exp(numeric) +} + +ex exp_eval(ex const & x) +{ + // exp(0) -> 1 + if (x.is_zero()) { + return exONE(); + } + // exp(n*Pi*I/2) -> {+1|+I|-1|-I} + ex TwoExOverPiI=(2*x)/(Pi*I); + if (TwoExOverPiI.info(info_flags::integer)) { + numeric z=mod(ex_to_numeric(TwoExOverPiI),numeric(4)); + if (z.is_equal(numZERO())) + return exONE(); + if (z.is_equal(numONE())) + return ex(I); + if (z.is_equal(numTWO())) + return exMINUSONE(); + if (z.is_equal(numTHREE())) + return ex(-I); + } + // exp(log(x)) -> x + if (is_ex_the_function(x, log)) + return x.op(0); + + // exp(float) + if (x.info(info_flags::numeric) && !x.info(info_flags::rational)) + return exp_evalf(x); + + return exp(x).hold(); +} + +ex exp_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return exp(x); +} + +REGISTER_FUNCTION(exp, exp_eval, exp_evalf, exp_diff, NULL); + +////////// +// natural logarithm +////////// + +ex log_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(log(x)) + + return log(ex_to_numeric(x)); // -> numeric log(numeric) +} + +ex log_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // log(1) -> 0 + if (x.is_equal(exONE())) + return exZERO(); + // log(-1) -> I*Pi + if (x.is_equal(exMINUSONE())) + return (I*Pi); + // log(I) -> Pi*I/2 + if (x.is_equal(I)) + return (I*Pi*numeric(1,2)); + // log(-I) -> -Pi*I/2 + if (x.is_equal(-I)) + return (I*Pi*numeric(-1,2)); + // log(0) -> throw singularity + if (x.is_equal(exZERO())) + throw(std::domain_error("log_eval(): log(0)")); + // log(float) + if (!x.info(info_flags::rational)) + return log_evalf(x); + } + + return log(x).hold(); +} + +ex log_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return power(x, -1); +} + +REGISTER_FUNCTION(log, log_eval, log_evalf, log_diff, NULL); + +////////// +// sine (trigonometric function) +////////// + +ex sin_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(sin(x)) + + return sin(ex_to_numeric(x)); // -> numeric sin(numeric) +} + +ex sin_eval(ex const & x) +{ + // sin(n*Pi) -> 0 + ex xOverPi=x/Pi; + if (xOverPi.info(info_flags::integer)) + return exZERO(); + + // sin((2n+1)*Pi/2) -> {+|-}1 + ex xOverPiMinusHalf=xOverPi-exHALF(); + if (xOverPiMinusHalf.info(info_flags::even)) + return exONE(); + else if (xOverPiMinusHalf.info(info_flags::odd)) + return exMINUSONE(); + + if (is_ex_exactly_of_type(x, function)) { + ex t=x.op(0); + // sin(asin(x)) -> x + if (is_ex_the_function(x, asin)) + return t; + // sin(acos(x)) -> (1-x^2)^(1/2) + if (is_ex_the_function(x, acos)) + return power(exONE()-power(t,exTWO()),exHALF()); + // sin(atan(x)) -> x*(1+x^2)^(-1/2) + if (is_ex_the_function(x, atan)) + return t*power(exONE()+power(t,exTWO()),exMINUSHALF()); + } + + // sin(float) -> float + if (x.info(info_flags::numeric) && !x.info(info_flags::rational)) + return sin_evalf(x); + + return sin(x).hold(); +} + +ex sin_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return cos(x); +} + +REGISTER_FUNCTION(sin, sin_eval, sin_evalf, sin_diff, NULL); + +////////// +// cosine (trigonometric function) +////////// + +ex cos_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(cos(x)) + + return cos(ex_to_numeric(x)); // -> numeric cos(numeric) +} + +ex cos_eval(ex const & x) +{ + // cos(n*Pi) -> {+|-}1 + ex xOverPi=x/Pi; + if (xOverPi.info(info_flags::even)) + return exONE(); + else if (xOverPi.info(info_flags::odd)) + return exMINUSONE(); + + // cos((2n+1)*Pi/2) -> 0 + ex xOverPiMinusHalf=xOverPi-exHALF(); + if (xOverPiMinusHalf.info(info_flags::integer)) + return exZERO(); + + if (is_ex_exactly_of_type(x, function)) { + ex t=x.op(0); + // cos(acos(x)) -> x + if (is_ex_the_function(x, acos)) + return t; + // cos(asin(x)) -> (1-x^2)^(1/2) + if (is_ex_the_function(x, asin)) + return power(exONE()-power(t,exTWO()),exHALF()); + // cos(atan(x)) -> (1+x^2)^(-1/2) + if (is_ex_the_function(x, atan)) + return power(exONE()+power(t,exTWO()),exMINUSHALF()); + } + + // cos(float) -> float + if (x.info(info_flags::numeric) && !x.info(info_flags::rational)) + return cos_evalf(x); + + return cos(x).hold(); +} + +ex cos_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return numMINUSONE()*sin(x); +} + +REGISTER_FUNCTION(cos, cos_eval, cos_evalf, cos_diff, NULL); + +////////// +// tangent (trigonometric function) +////////// + +ex tan_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(tan(x)) // -> numeric tan(numeric) + + return tan(ex_to_numeric(x)); +} + +ex tan_eval(ex const & x) +{ + // tan(n*Pi/3) -> {0|3^(1/2)|-(3^(1/2))} + ex ThreeExOverPi=numTHREE()*x/Pi; + if (ThreeExOverPi.info(info_flags::integer)) { + numeric z=mod(ex_to_numeric(ThreeExOverPi),numeric(3)); + if (z.is_equal(numZERO())) + return exZERO(); + if (z.is_equal(numONE())) + return power(exTHREE(),exHALF()); + if (z.is_equal(numTWO())) + return -power(exTHREE(),exHALF()); + } + + // tan((2n+1)*Pi/2) -> throw + ex ExOverPiMinusHalf=x/Pi-exHALF(); + if (ExOverPiMinusHalf.info(info_flags::integer)) + throw (std::domain_error("tan_eval(): infinity")); + + if (is_ex_exactly_of_type(x, function)) { + ex t=x.op(0); + // tan(atan(x)) -> x + if (is_ex_the_function(x, atan)) + return t; + // tan(asin(x)) -> x*(1+x^2)^(-1/2) + if (is_ex_the_function(x, asin)) + return t*power(exONE()-power(t,exTWO()),exMINUSHALF()); + // tan(acos(x)) -> (1-x^2)^(1/2)/x + if (is_ex_the_function(x, acos)) + return power(t,exMINUSONE())*power(exONE()-power(t,exTWO()),exHALF()); + } + + // tan(float) -> float + if (x.info(info_flags::numeric) && !x.info(info_flags::rational)) { + return tan_evalf(x); + } + + return tan(x).hold(); +} + +ex tan_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return (1+power(tan(x),exTWO())); +} + +REGISTER_FUNCTION(tan, tan_eval, tan_evalf, tan_diff, NULL); + +////////// +// inverse sine (arc sine) +////////// + +ex asin_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(asin(x)) + + return asin(ex_to_numeric(x)); // -> numeric asin(numeric) +} + +ex asin_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // asin(0) -> 0 + if (x.is_zero()) + return x; + // asin(1/2) -> Pi/6 + if (x.is_equal(exHALF())) + return numeric(1,6)*Pi; + // asin(1) -> Pi/2 + if (x.is_equal(exONE())) + return numeric(1,2)*Pi; + // asin(-1/2) -> -Pi/6 + if (x.is_equal(exMINUSHALF())) + return numeric(-1,6)*Pi; + // asin(-1) -> -Pi/2 + if (x.is_equal(exMINUSONE())) + return numeric(-1,2)*Pi; + // asin(float) -> float + if (!x.info(info_flags::rational)) + return asin_evalf(x); + } + + return asin(x).hold(); +} + +ex asin_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return power(1-power(x,exTWO()),exMINUSHALF()); +} + +REGISTER_FUNCTION(asin, asin_eval, asin_evalf, asin_diff, NULL); + +////////// +// inverse cosine (arc cosine) +////////// + +ex acos_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(acos(x)) + + return acos(ex_to_numeric(x)); // -> numeric acos(numeric) +} + +ex acos_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // acos(1) -> 0 + if (x.is_equal(exONE())) + return exZERO(); + // acos(1/2) -> Pi/3 + if (x.is_equal(exHALF())) + return numeric(1,3)*Pi; + // acos(0) -> Pi/2 + if (x.is_zero()) + return numeric(1,2)*Pi; + // acos(-1/2) -> 2/3*Pi + if (x.is_equal(exMINUSHALF())) + return numeric(2,3)*Pi; + // acos(-1) -> Pi + if (x.is_equal(exMINUSONE())) + return Pi; + // acos(float) -> float + if (!x.info(info_flags::rational)) + return acos_evalf(x); + } + + return acos(x).hold(); +} + +ex acos_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return numMINUSONE()*power(1-power(x,exTWO()),exMINUSHALF()); +} + +REGISTER_FUNCTION(acos, acos_eval, acos_evalf, acos_diff, NULL); + +////////// +// inverse tangent (arc tangent) +////////// + +ex atan_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(atan(x)) + + return atan(ex_to_numeric(x)); // -> numeric atan(numeric) +} + +ex atan_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // atan(0) -> 0 + if (x.is_equal(exZERO())) + return exZERO(); + // atan(float) -> float + if (!x.info(info_flags::rational)) + return atan_evalf(x); + } + + return atan(x).hold(); +} + +ex atan_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return power(1+x*x, -1); +} + +REGISTER_FUNCTION(atan, atan_eval, atan_evalf, atan_diff, NULL); + +////////// +// inverse tangent (atan2(y,x)) +////////// + +ex atan2_evalf(ex const & y, ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(y,numeric) + TYPECHECK(x,numeric) + END_TYPECHECK(atan2(y,x)) + + return atan(ex_to_numeric(y),ex_to_numeric(x)); // -> numeric atan(numeric) +} + +ex atan2_eval(ex const & y, ex const & x) +{ + if (y.info(info_flags::numeric) && !y.info(info_flags::rational) && + x.info(info_flags::numeric) && !x.info(info_flags::rational)) { + return atan2_evalf(y,x); + } + + return atan2(y,x).hold(); +} + +ex atan2_diff(ex const & y, ex const & x, unsigned diff_param) +{ + ASSERT(diff_param<2); + + if (diff_param==0) { + // d/dy atan(y,x) + return power(x*(1+y*y/(x*x)),-1); + } + // d/dx atan(y,x) + return -y*power(x*x+y*y,-1); +} + +REGISTER_FUNCTION(atan2, atan2_eval, atan2_evalf, atan2_diff, NULL); + +////////// +// hyperbolic sine (trigonometric function) +////////// + +ex sinh_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(sinh(x)) + + return sinh(ex_to_numeric(x)); // -> numeric sinh(numeric) +} + +ex sinh_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // sinh(0) -> 0 + if (x.is_zero()) + return exZERO(); + // sinh(float) -> float + if (!x.info(info_flags::rational)) + return sinh_evalf(x); + } + + if (is_ex_exactly_of_type(x, function)) { + ex t=x.op(0); + // sinh(asinh(x)) -> x + if (is_ex_the_function(x, asinh)) + return t; + // sinh(acosh(x)) -> (x-1)^(1/2) * (x+1)^(1/2) + if (is_ex_the_function(x, acosh)) + return power(t-exONE(),exHALF())*power(t+exONE(),exHALF()); + // sinh(atanh(x)) -> x*(1-x^2)^(-1/2) + if (is_ex_the_function(x, atanh)) + return t*power(exONE()-power(t,exTWO()),exMINUSHALF()); + } + + return sinh(x).hold(); +} + +ex sinh_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return cosh(x); +} + +REGISTER_FUNCTION(sinh, sinh_eval, sinh_evalf, sinh_diff, NULL); + +////////// +// hyperbolic cosine (trigonometric function) +////////// + +ex cosh_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(cosh(x)) + + return cosh(ex_to_numeric(x)); // -> numeric cosh(numeric) +} + +ex cosh_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // cosh(0) -> 1 + if (x.is_zero()) + return exONE(); + // cosh(float) -> float + if (!x.info(info_flags::rational)) + return cosh_evalf(x); + } + + if (is_ex_exactly_of_type(x, function)) { + ex t=x.op(0); + // cosh(acosh(x)) -> x + if (is_ex_the_function(x, acosh)) + return t; + // cosh(asinh(x)) -> (1+x^2)^(1/2) + if (is_ex_the_function(x, asinh)) + return power(exONE()+power(t,exTWO()),exHALF()); + // cosh(atanh(x)) -> (1-x^2)^(-1/2) + if (is_ex_the_function(x, atanh)) + return power(exONE()-power(t,exTWO()),exMINUSHALF()); + } + + return cosh(x).hold(); +} + +ex cosh_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return sinh(x); +} + +REGISTER_FUNCTION(cosh, cosh_eval, cosh_evalf, cosh_diff, NULL); + +////////// +// hyperbolic tangent (trigonometric function) +////////// + +ex tanh_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(tanh(x)) + + return tanh(ex_to_numeric(x)); // -> numeric tanh(numeric) +} + +ex tanh_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // tanh(0) -> 0 + if (x.is_zero()) + return exZERO(); + // tanh(float) -> float + if (!x.info(info_flags::rational)) + return tanh_evalf(x); + } + + if (is_ex_exactly_of_type(x, function)) { + ex t=x.op(0); + // tanh(atanh(x)) -> x + if (is_ex_the_function(x, atanh)) + return t; + // tanh(asinh(x)) -> x*(1+x^2)^(-1/2) + if (is_ex_the_function(x, asinh)) + return t*power(exONE()+power(t,exTWO()),exMINUSHALF()); + // tanh(acosh(x)) -> (x-1)^(1/2)*(x+1)^(1/2)/x + if (is_ex_the_function(x, acosh)) + return power(t-exONE(),exHALF())*power(t+exONE(),exHALF())*power(t,exMINUSONE()); + } + + return tanh(x).hold(); +} + +ex tanh_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return exONE()-power(tanh(x),exTWO()); +} + +REGISTER_FUNCTION(tanh, tanh_eval, tanh_evalf, tanh_diff, NULL); + +////////// +// inverse hyperbolic sine (trigonometric function) +////////// + +ex asinh_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(asinh(x)) + + return asinh(ex_to_numeric(x)); // -> numeric asinh(numeric) +} + +ex asinh_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // asinh(0) -> 0 + if (x.is_zero()) + return exZERO(); + // asinh(float) -> float + if (!x.info(info_flags::rational)) + return asinh_evalf(x); + } + + return asinh(x).hold(); +} + +ex asinh_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return power(1+power(x,exTWO()),exMINUSHALF()); +} + +REGISTER_FUNCTION(asinh, asinh_eval, asinh_evalf, asinh_diff, NULL); + +////////// +// inverse hyperbolic cosine (trigonometric function) +////////// + +ex acosh_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(acosh(x)) + + return acosh(ex_to_numeric(x)); // -> numeric acosh(numeric) +} + +ex acosh_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // acosh(0) -> Pi*I/2 + if (x.is_zero()) + return Pi*I*numeric(1,2); + // acosh(1) -> 0 + if (x.is_equal(exONE())) + return exZERO(); + // acosh(-1) -> Pi*I + if (x.is_equal(exMINUSONE())) + return Pi*I; + // acosh(float) -> float + if (!x.info(info_flags::rational)) + return acosh_evalf(x); + } + + return acosh(x).hold(); +} + +ex acosh_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return power(x-1,exMINUSHALF())*power(x+1,exMINUSHALF()); +} + +REGISTER_FUNCTION(acosh, acosh_eval, acosh_evalf, acosh_diff, NULL); + +////////// +// inverse hyperbolic tangent (trigonometric function) +////////// + +ex atanh_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(atanh(x)) + + return atanh(ex_to_numeric(x)); // -> numeric atanh(numeric) +} + +ex atanh_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // atanh(0) -> 0 + if (x.is_zero()) + return exZERO(); + // atanh({+|-}1) -> throw + if (x.is_equal(exONE()) || x.is_equal(exONE())) + throw (std::domain_error("atanh_eval(): infinity")); + // atanh(float) -> float + if (!x.info(info_flags::rational)) + return atanh_evalf(x); + } + + return atanh(x).hold(); +} + +ex atanh_diff(ex const & x, unsigned diff_param) +{ + ASSERT(diff_param==0); + + return power(exONE()-power(x,exTWO()),exMINUSONE()); +} + +REGISTER_FUNCTION(atanh, atanh_eval, atanh_evalf, atanh_diff, NULL); diff --git a/ginac/isospin.cpp b/ginac/isospin.cpp new file mode 100644 index 00000000..c8a58047 --- /dev/null +++ b/ginac/isospin.cpp @@ -0,0 +1,190 @@ +/** @file isospin.cpp + * + * Implementation of GiNaC's isospin objects. + * No real implementation yet, to be done. */ + +#include + +#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(&other); + if (serial==o->serial) { + return indexed::compare_same_type(other); + } + return serial < o->serial ? -1 : 1; +} + +ex isospin::simplify_ncmul(exvector const & v) const +{ + return simplified_ncmul(v); +} + +unsigned isospin::calchash(void) const +{ + hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555556U ^ + golden_ratio_hash(tinfo_key) ^ + serial)); + setflag(status_flags::hash_calculated); + return hashvalue; +} + +////////// +// virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +void isospin::setname(string const & n) +{ + name=n; +} + +// private + +string & isospin::autoname_prefix(void) +{ + static string * s=new string("isospin"); + return *s; +} + +////////// +// static member variables +////////// + +// private + +unsigned isospin::next_serial=0; + +////////// +// global constants +////////// + +const isospin some_isospin; +type_info const & typeid_isospin=typeid(some_isospin); + diff --git a/ginac/isospin.h b/ginac/isospin.h new file mode 100644 index 00000000..3a8e9307 --- /dev/null +++ b/ginac/isospin.h @@ -0,0 +1,75 @@ +/** @file isospin.h + * + * Interface to GiNaC's isospin objects. */ + +#ifndef _ISOSPIN_H_ +#define _ISOSPIN_H_ + +#include + +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(*(X).bp) + +#endif // ndef _ISOSPIN_H_ + + diff --git a/ginac/lorentzidx.cpp b/ginac/lorentzidx.cpp new file mode 100644 index 00000000..e53d8a85 --- /dev/null +++ b/ginac/lorentzidx.cpp @@ -0,0 +1,234 @@ +/** @file lorentzidx.cpp + * + * Implementation of GiNaC's lorentz indices. */ + +#include + +#include "ginac.h" +#include "utils.h" + +////////// +// default constructor, destructor, copy constructor assignment operator and helpers +////////// + +// public + +lorentzidx::lorentzidx() : orthogonal_only(false), dim_parallel_space(0) +{ + debugmsg("lorentzidx default constructor",LOGLEVEL_CONSTRUCT); + // serial is incremented in idx::idx() + name="mu"+ToString(serial); + tinfo_key=TINFO_LORENTZIDX; +} + +lorentzidx::~lorentzidx() +{ + debugmsg("lorentzidx destructor",LOGLEVEL_DESTRUCT); + destroy(0); +} + +lorentzidx::lorentzidx(lorentzidx const & other) +{ + debugmsg("lorentzidx copy constructor",LOGLEVEL_CONSTRUCT); + copy(other); +} + +lorentzidx const & lorentzidx::operator=(lorentzidx const & other) +{ + debugmsg("lorentzidx operator=",LOGLEVEL_ASSIGNMENT); + if (this != &other) { + destroy(1); + copy(other); + } + return *this; +} + +// protected + +void lorentzidx::copy(lorentzidx const & other) +{ + idx::copy(other); + orthogonal_only=other.orthogonal_only; + dim_parallel_space=other.dim_parallel_space; +} + +void lorentzidx::destroy(bool call_parent) +{ + if (call_parent) idx::destroy(call_parent); +} + +////////// +// other constructors +////////// + +// public + +lorentzidx::lorentzidx(bool cov, bool oonly, unsigned dimp) : + idx(cov), orthogonal_only(oonly), dim_parallel_space(dimp) +{ + debugmsg("lorentzidx constructor from bool",LOGLEVEL_CONSTRUCT); + // serial is incremented in idx::idx(bool) + if (oonly) { + name="muorth"+ToString(serial); + } else { + name="mu"+ToString(serial); + } + tinfo_key=TINFO_LORENTZIDX; +} + +lorentzidx::lorentzidx(string const & n, bool cov, bool oonly, unsigned dimp) + : idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp) +{ + debugmsg("lorentzidx constructor from string,bool,bool,unsigned", + LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_LORENTZIDX; +} + +lorentzidx::lorentzidx(char const * n, bool cov, bool oonly, unsigned dimp) + : idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp) +{ + debugmsg("lorentzidx constructor from char*,bool,bool,unsigned", + LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_LORENTZIDX; +} + +lorentzidx::lorentzidx(unsigned const v, bool cov) : idx(v,cov), + orthogonal_only(false), dim_parallel_space(0) +{ + debugmsg("lorentzidx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT); + tinfo_key=TINFO_LORENTZIDX; +} + +////////// +// functions overriding virtual functions from bases classes +////////// + +// public + +basic * lorentzidx::duplicate() const +{ + debugmsg("lorentzidx duplicate",LOGLEVEL_DUPLICATE); + return new lorentzidx(*this); +} + +void lorentzidx::printraw(ostream & os) const +{ + debugmsg("lorentzidx printraw",LOGLEVEL_PRINT); + + os << "lorentzidx("; + + if (symbolic) { + os << "symbolic,name=" << name; + } else { + os << "non symbolic,value=" << value; + } + + if (covariant) { + os << ",covariant"; + } else { + os << ",contravariant"; + } + + if (orthogonal_only) { + os << ",only orthogonal components at " << dim_parallel_space + << " parallel dimensions"; + } else { + os << ",parallel and orthogonal components"; + } + + os << ",serial=" << serial; + os << ",hash=" << hashvalue << ",flags=" << flags; + os << ")"; +} + +void lorentzidx::printtree(ostream & os, unsigned indent) const +{ + debugmsg("lorentzidx printtree",LOGLEVEL_PRINT); + + os << string(indent,' ') << "lorentzidx: "; + + if (symbolic) { + os << "symbolic,name=" << name; + } else { + os << "non symbolic,value=" << value; + } + + if (covariant) { + os << ",covariant"; + } else { + os << ",contravariant"; + } + + if (orthogonal_only) { + os << ",only orthogonal components at " << dim_parallel_space + << " parallel dimensions"; + } else { + os << ",parallel and orthogonal components"; + } + + os << ", serial=" << serial + << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")" + << ", flags=" << flags << endl; +} + +void lorentzidx::print(ostream & os, unsigned upper_precedence) const +{ + debugmsg("lorentzidx print",LOGLEVEL_PRINT); + + if (covariant) { + os << "_"; + } else { + os << "~"; + } + if (symbolic) { + os << name; + } else { + os << value; + } +} + +bool lorentzidx::info(unsigned inf) const +{ + if (inf==info_flags::lorentzidx) return true; + return idx::info(inf); +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +// public + +lorentzidx lorentzidx::create_anonymous_representative(void) const +{ + ASSERT(is_symbolic()); + lorentzidx i_copy(*this); + i_copy.serial=0; + i_copy.name="anonymous_representative"; + i_copy.covariant=false; + i_copy.clearflag(status_flags::dynallocated| + status_flags::hash_calculated); + return i_copy; +} + +////////// +// static member variables +////////// + +// none + +////////// +// global constants +////////// + +const lorentzidx some_lorentzidx; +type_info const & typeid_lorentzidx=typeid(some_lorentzidx); + + + diff --git a/ginac/lorentzidx.h b/ginac/lorentzidx.h new file mode 100644 index 00000000..99eae084 --- /dev/null +++ b/ginac/lorentzidx.h @@ -0,0 +1,71 @@ +/** @file lorentzidx.h + * + * Interface to GiNaC's lorentz indices. */ + +#ifndef _LORENTZIDX_H_ +#define _LORENTZIDX_H_ + +#include +#include + +#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(*(X).bp)) + +#endif // ndef _LORENTZIDX_H_ diff --git a/ginac/lst.cpp b/ginac/lst.cpp new file mode 100644 index 00000000..550d8863 --- /dev/null +++ b/ginac/lst.cpp @@ -0,0 +1,611 @@ +/** @file lst.cpp + * + * Implementation of GiNaC's lst. + * This file was generated automatically by container.pl. + * Please do not modify it directly, edit the perl script instead! + * container.pl options: $CONTAINER=lst + * $STLHEADER=list + * $reserve=0 + * $prepend=1 + * $let_op=1 + * $open_bracket=[ + * $close_bracket=] */ + +#include +#include + +#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(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(ihold(); + } + 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 + (const_cast(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 + (const_cast(other)); + if (seq.size()!=o.seq.size()) return false; + + exlist::const_iterator it1=seq.begin(); + exlist::const_iterator it2=o.seq.begin(); + + for (; it1!=seq.end(); ++it1, ++it2) { + if (!(*it1).is_equal(*it2)) return false; + } + + return true; +} + +unsigned lst::return_type(void) const +{ + return return_types::noncommutative_composite; +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// public + +lst & lst::append(ex const & b) +{ + ensure_if_modifiable(); + seq.push_back(b); + return *this; +} + +lst & lst::prepend(ex const & b) +{ + ensure_if_modifiable(); + seq.push_front(b); + return *this; +} + + +// protected + +void lst::printseq(ostream & os, char openbracket, char delim, + char closebracket, unsigned this_precedence, + unsigned upper_precedence) const +{ + if (this_precedence<=upper_precedence) os << openbracket; + if (seq.size()!=0) { + exlist::const_iterator it,it_last; + it=seq.begin(); + it_last=seq.end(); + --it_last; + for (; it!=it_last; ++it) { + (*it).bp->print(os,this_precedence); + os << delim; + } + (*it).bp->print(os,this_precedence); + } + if (this_precedence<=upper_precedence) os << closebracket; +} + +ex lst::thislst(exlist const & v) const +{ + return lst(v); +} + +ex lst::thislst(exlist * vp) const +{ + return lst(vp); +} + +////////// +// non-virtual functions in this class +////////// + +// public + +// none + +// protected + +bool lst::is_canonical() const +{ + if (seq.size()<=1) { return 1; } + + exlist::const_iterator it=seq.begin(); + exlist::const_iterator it_last=it; + for (++it; it!=seq.end(); it_last=it, ++it) { + if ((*it_last).compare(*it)>0) { + if ((*it_last).compare(*it)>0) { + cout << *it_last << ">" << *it << "\n"; + return 0; + } + } + } + return 1; +} + + +exlist lst::evalchildren(int level) const +{ + exlist s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).eval(level)); + } + return s; +} + +exlist lst::evalfchildren(int level) const +{ + exlist s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).evalf(level)); + } + return s; +} + +exlist lst::normalchildren(int level) const +{ + exlist s; + RESERVE(s,seq.size()); + + if (level==1) { + return seq; + } + if (level == -max_recursion_level) { + throw(std::runtime_error("max recursion level reached")); + } + --level; + for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).normal(level)); + } + return s; +} + +exlist lst::diffchildren(symbol const & y) const +{ + exlist s; + RESERVE(s,seq.size()); + for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).diff(y)); + } + return s; +} + +/* obsolete subschildren +exlist lst::subschildren(lst const & ls, lst const & lr) const +{ + exlist s; + RESERVE(s,seq.size()); + for (exlist::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).subs(ls,lr)); + } + return s; +} +*/ + +exlist * lst::subschildren(lst const & ls, lst const & lr) const +{ + // returns a NULL pointer if nothing had to be substituted + // returns a pointer to a newly created epvector otherwise + // (which has to be deleted somewhere else) + + exlist::const_iterator last=seq.end(); + exlist::const_iterator cit=seq.begin(); + while (cit!=last) { + ex const & subsed_ex=(*cit).subs(ls,lr); + if (!are_ex_trivially_equal(*cit,subsed_ex)) { + + // something changed, copy seq, subs and return it + exlist *s=new exlist; + RESERVE(*s,seq.size()); + + // copy parts of seq which are known not to have changed + exlist::const_iterator cit2=seq.begin(); + while (cit2!=cit) { + s->push_back(*cit2); + ++cit2; + } + // copy first changed element + s->push_back(subsed_ex); + ++cit2; + // copy rest + while (cit2!=last) { + s->push_back((*cit2).subs(ls,lr)); + ++cit2; + } + return s; + } + ++cit; + } + + return 0; // nothing has changed +} + +////////// +// static member variables +////////// + +// protected + +unsigned lst::precedence=10; + +////////// +// global constants +////////// + +const lst some_lst; +type_info const & typeid_lst=typeid(some_lst); + diff --git a/ginac/lst.h b/ginac/lst.h new file mode 100644 index 00000000..66af406b --- /dev/null +++ b/ginac/lst.h @@ -0,0 +1,116 @@ +/** @file lst.h + * + * Definition of GiNaC's lst. + * This file was generated automatically by container.pl. + * Please do not modify it directly, edit the perl script instead! + * container.pl options: $CONTAINER=lst + * $STLHEADER=list + * $reserve=0 + * $prepend=1 + * $let_op=1 + * $open_bracket=[ + * $close_bracket=] */ + +#ifndef _LST_H_ +#define _LST_H_ + +#include + +#include + +typedef list 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(*(X).bp)) + +#endif // ndef _LST_H_ + diff --git a/ginac/lst_suppl.cpp b/ginac/lst_suppl.cpp new file mode 100644 index 00000000..6280169f --- /dev/null +++ b/ginac/lst_suppl.cpp @@ -0,0 +1,14 @@ +/** @file lst_suppl.cpp + * + * Supplement to lst.cpp, contains the parts which were + * not automatically generated. */ + +#include "ginac.h" + +bool lst::info(unsigned inf) const +{ + if (inf==info_flags::list) return 1; + return basic::info(inf); +} + + diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp new file mode 100644 index 00000000..edf2a945 --- /dev/null +++ b/ginac/matrix.cpp @@ -0,0 +1,852 @@ +/** @file matrix.cpp + * + * Implementation of symbolic matrices */ + +#include +#include + +#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 const & m2) + : basic(TINFO_MATRIX), row(r), col(c), m(m2) +{ + debugmsg("matrix constructor from int,int,vector",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 tmp(row*col); + for (int i=0; i::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 m2(row*col); + --level; + for (int r=0; rsetflag(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 m2(row*col); + --level; + for (int r=0; r(const_cast(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 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 sum(this->m); + vector::iterator i; + vector::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 dif(this->m); + vector::iterator i; + vector::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 prod(row*other.col); + for (int i=0; i=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 trans(col*row); + + for (int r=0; r +int permutation_sign(vector s) +{ + if (s.size() < 2) + return 0; + int sigma=1; + for (typename vector::iterator i=s.begin(); i!=s.end()-1; ++i) { + for (typename vector::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 sigma(M.cols()); + for (int i=0; i::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; rzero_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 sol(v.row*v.col); + for (int c=0; c=0; --r) { + sol[r*v.col+c] = tmp[r*tmp.col+c]; + for (int i=r+1; i + +/** 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 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 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(*(X).bp)) + +#endif // ndef _MATRIX_H_ diff --git a/ginac/mul.cpp b/ginac/mul.cpp new file mode 100644 index 00000000..bf5e70df --- /dev/null +++ b/ginac/mul.cpp @@ -0,0 +1,994 @@ +/** @file mul.cpp + * + * Implementation of GiNaC's products of expressions. */ + +#include +#include + +#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 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(*(*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(*(*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 + 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_positionsetflag(status_flags::dynallocated | + status_flags::expanded)); + + // increment k[] + l=number_of_adds-1; + while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) { + k[l]=0; + l--; + } + if (l<0) break; + } + + return (new add(distrseq))->setflag(status_flags::dynallocated | + status_flags::expanded); +} +*/ + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +epvector * mul::expandchildren(unsigned options) const +{ + epvector::const_iterator last=seq.end(); + epvector::const_iterator cit=seq.begin(); + while (cit!=last) { + ex const & factor=recombine_pair_to_ex(*cit); + ex const & expanded_factor=factor.expand(options); + if (!are_ex_trivially_equal(factor,expanded_factor)) { + + // something changed, copy seq, eval and return it + epvector *s=new epvector; + s->reserve(seq.size()); + + // copy parts of seq which are known not to have changed + epvector::const_iterator cit2=seq.begin(); + while (cit2!=cit) { + s->push_back(*cit2); + ++cit2; + } + // copy first changed element + s->push_back(split_ex_to_pair(expanded_factor)); + ++cit2; + // copy rest + while (cit2!=last) { + s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options))); + ++cit2; + } + return s; + } + ++cit; + } + + return 0; // nothing has changed +} + +////////// +// static member variables +////////// + +// protected + +unsigned mul::precedence=50; + + +////////// +// global constants +////////// + +const mul some_mul; +type_info const & typeid_mul=typeid(some_mul); + + diff --git a/ginac/mul.h b/ginac/mul.h new file mode 100644 index 00000000..6f951c9a --- /dev/null +++ b/ginac/mul.h @@ -0,0 +1,103 @@ +/** @file mul.h + * + * Interface to GiNaC's products of expressions. */ + +#ifndef _MUL_H_ +#define _MUL_H_ + +class mul; + +#include "expairseq.h" + +/** Product of expressions. */ +class mul : public expairseq +{ + friend class add; + friend class ncmul; + friend class power; + +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers +public: + mul(); + ~mul(); + mul(mul const & other); + mul const & operator=(mul const & other); +protected: + void copy(mul const & other); + void destroy(bool call_parent); + + // other constructors +public: + mul(ex const & lh, ex const & rh); + mul(exvector const & v); + mul(epvector const & v); + //mul(epvector const & v, bool do_not_canonicalize=0); + mul(epvector const & v, ex const & oc); + mul(epvector * vp, ex const & oc); + mul(ex const & lh, ex const & mh, ex const & rh); + + // functions overriding virtual functions from bases classes +public: + basic * duplicate() const; + void printraw(ostream & os) const; + void print(ostream & os, unsigned upper_precedence) const; + void printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const; + bool info(unsigned inf) const; + int degree(symbol const & s) const; + int ldegree(symbol const & s) const; + ex coeff(symbol const & s, int const n=1) const; + ex eval(int level=0) const; + ex diff(symbol const & s) const; + ex series(symbol const & s, ex const & point, int order) const; + ex normal(lst &sym_lst, lst &repl_lst, int level=0) const; + numeric integer_content(void) const; + ex smod(numeric const &xi) const; + numeric max_coefficient(void) const; + exvector get_indices(void) const; + ex simplify_ncmul(exvector const & v) const; +protected: + int compare_same_type(basic const & other) const; + bool is_equal_same_type(basic const & other) const; + unsigned return_type(void) const; + unsigned return_type_tinfo(void) const; + ex thisexpairseq(epvector const & v, ex const & oc) const; + ex thisexpairseq(epvector * vp, ex const & oc) const; + void printpair(ostream & os, expair const & p, + unsigned upper_precedence) const; + expair split_ex_to_pair(ex const & e) const; + expair combine_ex_with_coeff_to_pair(ex const & e, + ex const & c) const; + expair combine_pair_with_coeff_to_pair(expair const & p, + ex const & c) const; + ex recombine_pair_to_ex(expair const & p) const; + bool expair_needs_further_processing(epp it); + ex default_overall_coeff(void) const; + void combine_overall_coeff(ex const & c); + void combine_overall_coeff(ex const & c1, ex const & c2); + bool can_make_flat(expair const & p) const; + ex expand(unsigned options=0) const; + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class +protected: + epvector * expandchildren(unsigned options) const; + +// member variables + +protected: + static unsigned precedence; +}; + +// global constants + +extern const mul some_mul; +extern type_info const & typeid_mul; + +#define ex_to_mul(X) static_cast(*(X).bp) + +#endif // ndef _MUL_H_ + diff --git a/ginac/ncmul.cpp b/ginac/ncmul.cpp new file mode 100644 index 00000000..560f7151 --- /dev/null +++ b/ginac/ncmul.cpp @@ -0,0 +1,570 @@ +/** @file ncmul.cpp + * + * Implementation of GiNaC's non-commutative products of expressions. */ + +#include +#include +#include + +#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 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; lsetflag(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 unsignedvector; +typedef vector 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 + 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()) { + // 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 + setflag(status_flags::dynallocated)); + } + + return (new mul(splitseq))->setflag(status_flags::dynallocated); + } + + return (new ncmul(assocseq))->setflag(status_flags::dynallocated | + status_flags::evaluated); +} + +exvector ncmul::get_indices(void) const +{ + // return union of indices of factors + exvector iv; + for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) { + exvector subiv=(*cit).get_indices(); + iv.reserve(iv.size()+subiv.size()); + for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) { + iv.push_back(*cit2); + } + } + return iv; +} + +ex ncmul::subs(lst const & ls, lst const & lr) const +{ + return ncmul(subschildren(ls, lr)); +} + +ex ncmul::thisexprseq(exvector const & v) const +{ + return (new ncmul(v))->setflag(status_flags::dynallocated); +} + +ex ncmul::thisexprseq(exvector * vp) const +{ + return (new ncmul(vp))->setflag(status_flags::dynallocated); +} + +// protected + +int ncmul::compare_same_type(basic const & other) const +{ + return exprseq::compare_same_type(other); +} + +unsigned ncmul::return_type(void) const +{ + if (seq.size()==0) { + // ncmul without factors: should not happen, but commutes + return return_types::commutative; + } + + bool all_commutative=1; + unsigned rt; + exvector::const_iterator cit_noncommutative_element; // point to first found nc element + + for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) { + rt=(*cit).return_type(); + if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc + if ((rt==return_types::noncommutative)&&(all_commutative)) { + // first nc element found, remember position + cit_noncommutative_element=cit; + all_commutative=0; + } + if ((rt==return_types::noncommutative)&&(!all_commutative)) { + // another nc element found, compare type_infos + if ((*cit_noncommutative_element).return_type_tinfo()!=(*cit).return_type_tinfo()) { + // diffent types -> mul is ncc + return return_types::noncommutative_composite; + } + } + } + // all factors checked + ASSERT(!all_commutative); // not all factors should commute, because this is a ncmul(); + return all_commutative ? return_types::commutative : return_types::noncommutative; +} + +unsigned ncmul::return_type_tinfo(void) const +{ + if (seq.size()==0) { + // mul without factors: should not happen + return tinfo_key; + } + // return type_info of first noncommutative element + for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) { + if ((*cit).return_type()==return_types::noncommutative) { + return (*cit).return_type_tinfo(); + } + } + // no noncommutative element found, should not happen + return tinfo_key; +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +exvector ncmul::expandchildren(unsigned options) const +{ + exvector s; + s.reserve(seq.size()); + + for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { + s.push_back((*it).expand(options)); + } + return s; +} + +exvector const & ncmul::get_factors(void) const +{ + return seq; +} + +////////// +// static member variables +////////// + +// protected + +unsigned ncmul::precedence=50; + + +////////// +// global constants +////////// + +const ncmul some_ncmul; +type_info const & typeid_ncmul=typeid(some_ncmul); + +////////// +// friend functions +////////// + +ex nonsimplified_ncmul(exvector const & v) +{ + return (new ncmul(v))->setflag(status_flags::dynallocated); +} + +ex simplified_ncmul(exvector const & v) +{ + if (v.size()==0) { + return exONE(); + } else if (v.size()==1) { + return v[0]; + } + return (new ncmul(v))->setflag(status_flags::dynallocated | + status_flags::evaluated); +} + + diff --git a/ginac/ncmul.h b/ginac/ncmul.h new file mode 100644 index 00000000..1b833b0b --- /dev/null +++ b/ginac/ncmul.h @@ -0,0 +1,96 @@ +/** @file ncmul.h + * + * Interface to GiNaC's non-commutative products of expressions. */ + +#ifndef _NCMUL_H_ +#define _NCMUL_H_ + +#include "exprseq.h" + +class ncmul; + +/** Non-commutative product of expressions. */ +class ncmul : public exprseq +{ + friend class power; + friend ex nonsimplified_ncmul(exvector const & v); + friend ex simplified_ncmul(exvector const & v); + +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers +public: + ncmul(); + ~ncmul(); + ncmul(ncmul const & other); + ncmul const & operator=(ncmul const & other); +protected: + void copy(ncmul const & other); + void destroy(bool call_parent); + + // other constructors +public: + ncmul(ex const & lh, ex const & rh); + ncmul(ex const & f1, ex const & f2, ex const & f3); + ncmul(ex const & f1, ex const & f2, ex const & f3, + ex const & f4); + ncmul(ex const & f1, ex const & f2, ex const & f3, + ex const & f4, ex const & f5); + ncmul(ex const & f1, ex const & f2, ex const & f3, + ex const & f4, ex const & f5, ex const & f6); + ncmul(exvector const & v, bool discardable=false); + ncmul(exvector * vp); // vp will be deleted + + // functions overriding virtual functions from bases classes +public: + basic * duplicate() const; + void printraw(ostream & os) const; + void print(ostream & os, unsigned upper_precedence) const; + void printcsrc(ostream & os, unsigned upper_precedence) const; + bool info(unsigned inf) const; + int degree(symbol const & s) const; + int ldegree(symbol const & s) const; + ex expand(unsigned options=0) const; + ex coeff(symbol const & s, int const n=1) const; + ex eval(int level=0) const; + ex diff(symbol const & s) const; + ex subs(lst const & ls, lst const & lr) const; + exvector get_indices(void) const; + ex thisexprseq(exvector const & v) const; + ex thisexprseq(exvector * vp) const; +protected: + int compare_same_type(basic const & other) const; + unsigned return_type(void) const; + unsigned return_type_tinfo(void) const; + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class +protected: + unsigned count_factors(ex const & e) const; + void append_factors(exvector & v, ex const & e) const; + exvector expandchildren(unsigned options) const; +public: + exvector const & get_factors(void) const; + +// member variables + +protected: + static unsigned precedence; +}; + +// global constants + +extern const ncmul some_ncmul; +extern type_info const & typeid_ncmul; + +// friend funtions + +ex nonsimplified_ncmul(exvector const & v); +ex simplified_ncmul(exvector const & v); + +#define ex_to_ncmul(X) static_cast(*(X).bp) + +#endif // ndef _NCMUL_H_ + diff --git a/ginac/normal.cpp b/ginac/normal.cpp new file mode 100644 index 00000000..614b1db1 --- /dev/null +++ b/ginac/normal.cpp @@ -0,0 +1,1452 @@ +/** @file normal.cpp + * + * This file implements several functions that work on univariate and + * multivariate polynomials and rational functions. + * These functions include polynomial quotient and remainder, GCD and LCM + * computation, square-free factorization and rational function normalization. + */ + +#include + +#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(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 + +/** 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_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(e.bp), v); + } else if (is_ex_exactly_of_type(e, add) || is_ex_exactly_of_type(e, mul)) { + for (int i=0; isym)); + 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; iinteger_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 + +typedef pair ex2; +typedef pair 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_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 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 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=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; inormal(sym_lst, repl_lst, level-1).expand(); + if (is_ex_exactly_of_type(n, add)) { + epvector::const_iterator bit = (static_cast(n.bp))->seq.begin(), bitend = (static_cast(n.bp))->seq.end(); + while (bit != bitend) { + o.push_back(recombine_pair_to_ex(*bit)); + bit++; + } + o.push_back((static_cast(n.bp))->overall_coeff); + } else + o.push_back(n); + it++; + } + o.push_back(overall_coeff.bp->normal(sym_lst, repl_lst, level-1)); + + // Determine common denominator + ex den = exONE(); + exvector::const_iterator ait = o.begin(), aitend = o.end(); + while (ait != aitend) { + den = lcm((*ait).denom(false), den, false); + ait++; + } + + // Add fractions + if (den.is_equal(exONE())) + return (new add(o))->setflag(status_flags::dynallocated); + else { + exvector num_seq; + for (ait=o.begin(); ait!=aitend; ait++) { + ex q; + if (!divide(den, (*ait).denom(false), q, false)) { + // should not happen + throw(std::runtime_error("invalid expression in add::normal, division failed")); + } + num_seq.push_back((*ait).numer(false) * q); + } + ex num = add(num_seq); + + // Cancel common factors from num/den + return frac_cancel(num, den); + } +} + + +/** Implementation of ex::normal() for a product. It cancels common factors + * from fractions. + * @see ex::normal() */ +ex mul::normal(lst &sym_lst, lst &repl_lst, int level) const +{ + // Normalize children + exvector o; + o.reserve(seq.size()+1); + epvector::const_iterator it = seq.begin(), itend = seq.end(); + while (it != itend) { + o.push_back(recombine_pair_to_ex(*it).bp->normal(sym_lst, repl_lst, level-1)); + it++; + } + o.push_back(overall_coeff.bp->normal(sym_lst, repl_lst, level-1)); + ex n = (new mul(o))->setflag(status_flags::dynallocated); + return frac_cancel(n.numer(false), n.denom(false)); +} + + +/** Implementation of ex::normal() for powers. It normalizes the basis, + * distributes integer exponents to numerator and denominator, and replaces + * non-integer powers by temporary symbols. + * @see ex::normal */ +ex power::normal(lst &sym_lst, lst &repl_lst, int level) const +{ + if (exponent.info(info_flags::integer)) { + // Integer powers are distributed + ex n = basis.bp->normal(sym_lst, repl_lst, level-1); + ex num = n.numer(false); + ex den = n.denom(false); + return power(num, exponent) / power(den, exponent); + } else { + // Non-integer powers are replaced by temporary symbol (after normalizing basis) + ex n = power(basis.bp->normal(sym_lst, repl_lst, level-1), exponent); + return replace_with_symbol(n, sym_lst, repl_lst); + } +} + + +/** Implementation of ex::normal() for series. It normalizes each coefficient and + * replaces the series by a temporary symbol. + * @see ex::normal */ +ex series::normal(lst &sym_lst, lst &repl_lst, int level) const +{ + epvector new_seq; + new_seq.reserve(seq.size()); + + epvector::const_iterator it = seq.begin(), itend = seq.end(); + while (it != itend) { + new_seq.push_back(expair(it->rest.normal(), it->coeff)); + it++; + } + + ex n = series(var, point, new_seq); + return replace_with_symbol(n, sym_lst, repl_lst); +} + + +/** Normalization of rational functions. + * This function converts an expression to its normal form + * "numerator/denominator", where numerator and denominator are (relatively + * prime) polynomials. Any subexpressions which are not rational functions + * (like non-rational numbers, non-integer powers or functions like Sin(), + * Cos() etc.) are replaced by temporary symbols which are re-substituted by + * the (normalized) subexpressions before normal() returns (this way, any + * expression can be treated as a rational function). normal() is applied + * recursively to arguments of functions etc. + * + * @param level maximum depth of recursion + * @return normalized expression */ +ex ex::normal(int level) const +{ + lst sym_lst, repl_lst; + ex e = bp->normal(sym_lst, repl_lst, level); + if (sym_lst.nops() > 0) + return e.subs(sym_lst, repl_lst); + else + return e; +} diff --git a/ginac/normal.h b/ginac/normal.h new file mode 100644 index 00000000..451d1555 --- /dev/null +++ b/ginac/normal.h @@ -0,0 +1,35 @@ +/** @file normal.h + * + * Functions for polynomial quotient and remainder, GCD and LCM computation + * and square-free factorization. */ + +#ifndef NORMAL_H +#define NORMAL_H + +#include "ex.h" + +class symbol; + + +// Quotient q(x) of polynomials a(x) and b(x) in Q[x], so that a(x)=b(x)*q(x)+r(x) +extern ex quo(const ex &a, const ex &b, const symbol &x, bool check_args = true); + +// Remainder r(x) of polynomials a(x) and b(x) in Q[x], so that a(x)=b(x)*q(x)+r(x) +extern ex rem(const ex &a, const ex &b, const symbol &x, bool check_args = true); + +// Pseudo-remainder of polynomials a(x) and b(x) in Z[x] +extern ex prem(const ex &a, const ex &b, const symbol &x, bool check_args = true); + +// Exact polynomial division of a(X) by b(X) in Q[X] (quotient returned in q), returns false when exact division fails +extern bool divide(const ex &a, const ex &b, ex &q, bool check_args = true); + +// Polynomial GCD in Z[X], cofactors are returned in ca and cb, if desired +extern ex gcd(const ex &a, const ex &b, ex *ca = NULL, ex *cb = NULL, bool check_args = true); + +// Polynomial LCM in Z[X] +extern ex lcm(const ex &a, const ex &b, bool check_args = true); + +// Square-free factorization of a polynomial a(x) +extern ex sqrfree(const ex &a, const symbol &x); + +#endif diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp new file mode 100644 index 00000000..c189c3d7 --- /dev/null +++ b/ginac/numeric.cpp @@ -0,0 +1,1341 @@ +/** @file numeric.cpp + * + * This file contains the interface to the underlying bignum package. + * Its most important design principle is to completely hide the inner + * working of that other package from the user of GiNaC. It must either + * provide implementation of arithmetic operators and numerical evaluation + * of special functions or implement the interface to the bignum package. */ + +#include +#include + +#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 +#else +#include +#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(const_cast(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(&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((new numeric((*value)+(*other.value)))-> + setflag(status_flags::dynallocated)); +} + +numeric const & numeric::sub_dyn(numeric const & other) const +{ + return static_cast((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((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((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((new numeric(exp(*other.value * log(*value))))-> + setflag(status_flags::dynallocated)); + } else { + if ( !zerop(*other.value) ) { // 0^(n/m) + return static_cast((new numeric(0))-> + setflag(status_flags::dynallocated)); + } else { // raise FPE (0^0 requested) + return static_cast((new numeric(1/(*other.value)))-> + setflag(status_flags::dynallocated)); + } + } + } else { // default -> CLN + return static_cast((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(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(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(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(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(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(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 evenresults; + static int highest_evenresult = -1; + static vector oddresults; + static int highest_oddresult = -1; + + if ( nn == numeric(-1) ) { + return numONE(); + } + if ( !nn.is_nonneg_integer() ) { + throw (std::range_error("numeric::doublefactorial(): argument must be integer >= -1")); + } + if ( nn.is_even() ) { + int n = nn.div(numTWO()).to_int(); + if ( n <= highest_evenresult ) { + return evenresults[n]; + } + if ( evenresults.capacity() < (unsigned)(n+1) ) { + evenresults.reserve(n+1); + } + if ( highest_evenresult < 0 ) { + evenresults.push_back(numONE()); + highest_evenresult=0; + } + for (int i=highest_evenresult+1; i<=n; i++) { + evenresults.push_back(numeric(evenresults[i-1].mul(numeric(i*2)))); + } + highest_evenresult=n; + return evenresults[n]; + } else { + int n = nn.sub(numONE()).div(numTWO()).to_int(); + if ( n <= highest_oddresult ) { + return oddresults[n]; + } + if ( oddresults.capacity() < (unsigned)n ) { + oddresults.reserve(n+1); + } + if ( highest_oddresult < 0 ) { + oddresults.push_back(numONE()); + highest_oddresult=0; + } + for (int i=highest_oddresult+1; i<=n; i++) { + oddresults.push_back(numeric(oddresults[i-1].mul(numeric(i*2+1)))); + } + highest_oddresult=n; + return oddresults[n]; + } +} + +/** The Binomial function. It computes the binomial coefficients. If the + * arguments are both nonnegative integers and 0 <= k <= n, then + * binomial(n, k) = n!/k!/(n-k)! which is the number of ways of choosing k + * objects from n distinct objects. If k > n, then binomial(n,k) returns 0. */ +numeric binomial(numeric const & n, numeric const & k) +{ + if (n.is_nonneg_integer() && k.is_nonneg_integer()) { + return numeric(binomial(n.to_int(),k.to_int())); // -> CLN + } else { + // should really be gamma(n+1)/(gamma(r+1)/gamma(n-r+1) + return numeric(0); + } + // return factorial(n).div(factorial(k).mul(factorial(n.sub(k)))); +} + +/** Absolute value. */ +numeric abs(numeric const & x) +{ + return abs(*x.value); // -> CLN +} + +/** Modulus (in positive representation). + * In general, mod(a,b) has the sign of b or is zero, and rem(a,b) has the + * sign of a or is zero. This is different from Maple's modp, where the sign + * of b is ignored. It is in agreement with Mathematica's Mod. + * + * @return a mod b in the range [0,abs(b)-1] with sign of b if both are + * integer, 0 otherwise. */ +numeric mod(numeric const & a, numeric const & b) +{ + if (a.is_integer() && b.is_integer()) { + return mod(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + } + else { + return numZERO(); // Throw? + } +} + +/** Modulus (in symmetric representation). + * Equivalent to Maple's mods. + * + * @return a mod b in the range [-iquo(abs(m)-1,2), iquo(abs(m),2)]. */ +numeric smod(numeric const & a, numeric const & b) +{ + if (a.is_integer() && b.is_integer()) { + cl_I b2 = The(cl_I)(ceiling1(The(cl_I)(*b.value) / 2)) - 1; + return mod(The(cl_I)(*a.value) + b2, The(cl_I)(*b.value)) - b2; + } else { + return numZERO(); // Throw? + } +} + +/** Numeric integer remainder. + * Equivalent to Maple's irem(a,b) as far as sign conventions are concerned. + * In general, mod(a,b) has the sign of b or is zero, and irem(a,b) has the + * sign of a or is zero. + * + * @return remainder of a/b if both are integer, 0 otherwise. */ +numeric irem(numeric const & a, numeric const & b) +{ + if (a.is_integer() && b.is_integer()) { + return rem(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + } + else { + return numZERO(); // Throw? + } +} + +/** Numeric integer remainder. + * Equivalent to Maple's irem(a,b,'q') it obeyes the relation + * irem(a,b,q) == a - q*b. In general, mod(a,b) has the sign of b or is zero, + * and irem(a,b) has the sign of a or is zero. + * + * @return remainder of a/b and quotient stored in q if both are integer, + * 0 otherwise. */ +numeric irem(numeric const & a, numeric const & b, numeric & q) +{ + if (a.is_integer() && b.is_integer()) { // -> CLN + cl_I_div_t rem_quo = truncate2(The(cl_I)(*a.value), The(cl_I)(*b.value)); + q = rem_quo.quotient; + return rem_quo.remainder; + } + else { + q = numZERO(); + return numZERO(); // Throw? + } +} + +/** Numeric integer quotient. + * Equivalent to Maple's iquo as far as sign conventions are concerned. + * + * @return truncated quotient of a/b if both are integer, 0 otherwise. */ +numeric iquo(numeric const & a, numeric const & b) +{ + if (a.is_integer() && b.is_integer()) { + return truncate1(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + } else { + return numZERO(); // Throw? + } +} + +/** Numeric integer quotient. + * Equivalent to Maple's iquo(a,b,'r') it obeyes the relation + * r == a - iquo(a,b,r)*b. + * + * @return truncated quotient of a/b and remainder stored in r if both are + * integer, 0 otherwise. */ +numeric iquo(numeric const & a, numeric const & b, numeric & r) +{ + if (a.is_integer() && b.is_integer()) { // -> CLN + cl_I_div_t rem_quo = truncate2(The(cl_I)(*a.value), The(cl_I)(*b.value)); + r = rem_quo.remainder; + return rem_quo.quotient; + } else { + r = numZERO(); + return numZERO(); // Throw? + } +} + +/** Numeric square root. + * If possible, sqrt(z) should respect squares of exact numbers, i.e. sqrt(4) + * should return integer 2. + * + * @param z numeric argument + * @return square root of z. Branch cut along negative real axis, the negative + * real axis itself where imag(z)==0 and real(z)<0 belongs to the upper part + * where imag(z)>0. */ +numeric sqrt(numeric const & z) +{ + return sqrt(*z.value); // -> CLN +} + +/** Integer numeric square root. */ +numeric isqrt(numeric const & x) +{ + if (x.is_integer()) { + cl_I root; + isqrt(The(cl_I)(*x.value), &root); // -> CLN + return root; + } else + return numZERO(); // Throw? +} + +/** Greatest Common Divisor. + * + * @return The GCD of two numbers if both are integer, a numerical 1 + * if they are not. */ +numeric gcd(numeric const & a, numeric const & b) +{ + if (a.is_integer() && b.is_integer()) + return gcd(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + else + return numONE(); +} + +/** Least Common Multiple. + * + * @return The LCM of two numbers if both are integer, the product of those + * two numbers if they are not. */ +numeric lcm(numeric const & a, numeric const & b) +{ + if (a.is_integer() && b.is_integer()) + return lcm(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + else + return *a.value * *b.value; +} + +ex PiEvalf(void) +{ + return numeric(cl_pi(cl_default_float_format)); // -> CLN +} + +ex EulerGammaEvalf(void) +{ + return numeric(cl_eulerconst(cl_default_float_format)); // -> CLN +} + +ex CatalanEvalf(void) +{ + return numeric(cl_catalanconst(cl_default_float_format)); // -> CLN +} + +// It initializes to 17 digits, because in CLN cl_float_format(17) turns out to +// be 61 (<64) while cl_float_format(18)=65. We want to have a cl_LF instead +// of cl_SF, cl_FF or cl_DF but everything else is basically arbitrary. +_numeric_digits::_numeric_digits() + : digits(17) +{ + assert(!too_late); + too_late = true; + cl_default_float_format = cl_float_format(17); +} + +_numeric_digits& _numeric_digits::operator=(long prec) +{ + digits=prec; + cl_default_float_format = cl_float_format(prec); + return *this; +} + +_numeric_digits::operator long() +{ + return (long)digits; +} + +void _numeric_digits::print(ostream & os) const +{ + debugmsg("_numeric_digits print", LOGLEVEL_PRINT); + os << digits; +} + +ostream& operator<<(ostream& os, _numeric_digits const & e) +{ + e.print(os); + return os; +} + +////////// +// static member variables +////////// + +// private + +bool _numeric_digits::too_late = false; + +/** Accuracy in decimal digits. Only object of this type! Can be set using + * assignment from C++ unsigned ints and evaluated like any built-in type. */ +_numeric_digits Digits; diff --git a/ginac/numeric.h b/ginac/numeric.h new file mode 100644 index 00000000..0b2d28e3 --- /dev/null +++ b/ginac/numeric.h @@ -0,0 +1,307 @@ +/** @file numeric.h + * + * Makes the interface to the underlying bignum package available. */ + +#ifndef _NUMERIC_H_ +#define _NUMERIC_H_ + +#include + +#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(*(X).bp) + + +#endif // ndef _NUMERIC_H_ diff --git a/ginac/operators.cpp b/ginac/operators.cpp new file mode 100644 index 00000000..abd5061c --- /dev/null +++ b/ginac/operators.cpp @@ -0,0 +1,382 @@ +/** @file operators.cpp + * + * Implementation of GiNaC's overloaded operators. */ + +#include +#include + +#include "ginac.h" + +// binary arithmetic operators ex with ex + +ex operator+(ex const & lh, ex const & rh) +{ + debugmsg("operator+(ex,ex)",LOGLEVEL_OPERATOR); + return lh.exadd(rh); +} + +ex operator-(ex const & lh, ex const & rh) +{ + debugmsg("operator-(ex,ex)",LOGLEVEL_OPERATOR); + return lh.exadd(rh.exmul(exMINUSONE())); +} + +ex operator*(ex const & lh, ex const & rh) +{ + debugmsg("operator*(ex,ex)",LOGLEVEL_OPERATOR); + return lh.exmul(rh); +} + +ex operator/(ex const & lh, ex const & rh) +{ + debugmsg("operator*(ex,ex)",LOGLEVEL_OPERATOR); + return lh.exmul(power(rh,exMINUSONE())); +} + +ex operator%(ex const & lh, ex const & rh) +{ + debugmsg("operator%(ex,ex)",LOGLEVEL_OPERATOR); + return lh.exncmul(rh); +} + +/* + +// binary arithmetic operators ex with numeric + +ex operator+(ex const & lh, numeric const & rh) +{ + debugmsg("operator+(ex,numeric)",LOGLEVEL_OPERATOR); + return lh+ex(rh); +} + +ex operator-(ex const & lh, numeric const & rh) +{ + debugmsg("operator-(ex,numeric)",LOGLEVEL_OPERATOR); + return lh-ex(rh); +} + +ex operator*(ex const & lh, numeric const & rh) +{ + debugmsg("operator*(ex,numeric)",LOGLEVEL_OPERATOR); + return lh*ex(rh); +} + +ex operator/(ex const & lh, numeric const & rh) +{ + debugmsg("operator/(ex,numeric)",LOGLEVEL_OPERATOR); + return lh/ex(rh); +} + +ex operator%(ex const & lh, numeric const & rh) +{ + debugmsg("operator%(ex,numeric)",LOGLEVEL_OPERATOR); + return lh%ex(rh); +} + +// binary arithmetic operators numeric with ex + +ex operator+(numeric const & lh, ex const & rh) +{ + debugmsg("operator+(numeric,ex)",LOGLEVEL_OPERATOR); + return ex(lh)+rh; +} + +ex operator-(numeric const & lh, ex const & rh) +{ + debugmsg("operator-(numeric,ex)",LOGLEVEL_OPERATOR); + return ex(lh)-rh; +} + +ex operator*(numeric const & lh, ex const & rh) +{ + debugmsg("operator*(numeric,ex)",LOGLEVEL_OPERATOR); + return ex(lh)*rh; +} + +ex operator/(numeric const & lh, ex const & rh) +{ + debugmsg("operator/(numeric,ex)",LOGLEVEL_OPERATOR); + return ex(lh)/rh; +} + +ex operator%(numeric const & lh, ex const & rh) +{ + debugmsg("operator%(numeric,ex)",LOGLEVEL_OPERATOR); + return ex(lh)%rh; +} + +*/ + +// binary arithmetic operators numeric with numeric + +numeric operator+(numeric const & lh, numeric const & rh) +{ + debugmsg("operator+(numeric,numeric)",LOGLEVEL_OPERATOR); + return lh.add(rh); +} + +numeric operator-(numeric const & lh, numeric const & rh) +{ + debugmsg("operator-(numeric,numeric)",LOGLEVEL_OPERATOR); + return lh.sub(rh); +} + +numeric operator*(numeric const & lh, numeric const & rh) +{ + debugmsg("operator*(numeric,numeric)",LOGLEVEL_OPERATOR); + return lh.mul(rh); +} + +numeric operator/(numeric const & lh, numeric const & rh) +{ + debugmsg("operator/(numeric,ex)",LOGLEVEL_OPERATOR); + return lh.div(rh); +} + +// binary arithmetic assignment operators with ex + +ex const & operator+=(ex & lh, ex const & rh) +{ + debugmsg("operator+=(ex,ex)",LOGLEVEL_OPERATOR); + return (lh=lh+rh); +} + +ex const & operator-=(ex & lh, ex const & rh) +{ + debugmsg("operator-=(ex,ex)",LOGLEVEL_OPERATOR); + return (lh=lh-rh); +} + +ex const & operator*=(ex & lh, ex const & rh) +{ + debugmsg("operator*=(ex,ex)",LOGLEVEL_OPERATOR); + return (lh=lh*rh); +} + +ex const & operator/=(ex & lh, ex const & rh) +{ + debugmsg("operator/=(ex,ex)",LOGLEVEL_OPERATOR); + return (lh=lh/rh); +} + +ex const & operator%=(ex & lh, ex const & rh) +{ + debugmsg("operator%=(ex,ex)",LOGLEVEL_OPERATOR); + return (lh=lh%rh); +} + +/* + +// binary arithmetic assignment operators with numeric + +ex const & operator+=(ex & lh, numeric const & rh) +{ + debugmsg("operator+=(ex,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh+ex(rh)); +} + +ex const & operator-=(ex & lh, numeric const & rh) +{ + debugmsg("operator-=(ex,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh-ex(rh)); +} + +ex const & operator*=(ex & lh, numeric const & rh) +{ + debugmsg("operator*=(ex,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh*ex(rh)); +} + +ex const & operator/=(ex & lh, numeric const & rh) +{ + debugmsg("operator/=(ex,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh/ex(rh)); +} + +ex const & operator%=(ex & lh, numeric const & rh) +{ + debugmsg("operator%=(ex,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh%ex(rh)); +} + +*/ + +// binary arithmetic assignment operators with numeric + +numeric const & operator+=(numeric & lh, numeric const & rh) +{ + debugmsg("operator+=(numeric,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh.add(rh)); +} + +numeric const & operator-=(numeric & lh, numeric const & rh) +{ + debugmsg("operator-=(numeric,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh.sub(rh)); +} + +numeric const & operator*=(numeric & lh, numeric const & rh) +{ + debugmsg("operator*=(numeric,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh.mul(rh)); +} + +numeric const & operator/=(numeric & lh, numeric const & rh) +{ + debugmsg("operator/=(numeric,numeric)",LOGLEVEL_OPERATOR); + return (lh=lh.div(rh)); +} + +// unary operators + +ex operator+(ex const & lh) +{ + return lh; +} + +ex operator-(ex const & lh) +{ + return exMINUSONE()*lh; +} + +numeric operator+(numeric const & lh) +{ + return lh; +} + +numeric operator-(numeric const & lh) +{ + return (numeric(-1)*lh); +} + +// binary relational operators ex with ex + +relational operator==(ex const & lh, ex const & rh) +{ + debugmsg("operator==(ex,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::equal); +} + +relational operator!=(ex const & lh, ex const & rh) +{ + debugmsg("operator!=(ex,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::not_equal); +} + +relational operator<(ex const & lh, ex const & rh) +{ + debugmsg("operator<(ex,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::less); +} + +relational operator<=(ex const & lh, ex const & rh) +{ + debugmsg("operator<=(ex,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::less_or_equal); +} + +relational operator>(ex const & lh, ex const & rh) +{ + debugmsg("operator>(ex,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::greater); +} + +relational operator>=(ex const & lh, ex const & rh) +{ + debugmsg("operator>=(ex,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::greater_or_equal); +} + +/* + +// binary relational operators ex with numeric + +relational operator==(ex const & lh, numeric const & rh) +{ + debugmsg("operator==(ex,numeric)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::equal); +} + +relational operator!=(ex const & lh, numeric const & rh) +{ + debugmsg("operator!=(ex,numeric)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::not_equal); +} + +relational operator<(ex const & lh, numeric const & rh) +{ + debugmsg("operator<(ex,numeric)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::less); +} + +relational operator<=(ex const & lh, numeric const & rh) +{ + debugmsg("operator<=(ex,numeric)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::less_or_equal); +} + +relational operator>(ex const & lh, numeric const & rh) +{ + debugmsg("operator>(ex,numeric)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::greater); +} + +relational operator>=(ex const & lh, numeric const & rh) +{ + debugmsg("operator>=(ex,numeric)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::greater_or_equal); +} + +// binary relational operators numeric with ex + +relational operator==(numeric const & lh, ex const & rh) +{ + debugmsg("operator==(numeric,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::equal); +} + +relational operator!=(numeric const & lh, ex const & rh) +{ + debugmsg("operator!=(numeric,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::not_equal); +} + +relational operator<(numeric const & lh, ex const & rh) +{ + debugmsg("operator<(numeric,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::less); +} + +relational operator<=(numeric const & lh, ex const & rh) +{ + debugmsg("operator<=(numeric,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::less_or_equal); +} + +relational operator>(numeric const & lh, ex const & rh) +{ + debugmsg("operator>(numeric,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::greater); +} + +relational operator>=(numeric const & lh, ex const & rh) +{ + debugmsg("operator>=(numeric,ex)",LOGLEVEL_OPERATOR); + return relational(lh,rh,relational::greater_or_equal); +} + +*/ + +// input/output stream operators + +ostream & operator<<(ostream & os, ex const & e) +{ + e.print(os); + return os; +} + +istream & operator>>(istream & is, ex & e) +{ + throw(std::logic_error("input from streams not yet implemented")); +} + diff --git a/ginac/operators.h b/ginac/operators.h new file mode 100644 index 00000000..dfd985f5 --- /dev/null +++ b/ginac/operators.h @@ -0,0 +1,110 @@ +/** @file operators.h + * + * Interface to GiNaC's overloaded operators. */ + +#ifndef _OPERATORS_H_ +#define _OPERATORS_H_ + +#include +#include "basic.h" +#include "ex.h" +#include "numeric.h" +#include "relational.h" + + +// binary arithmetic operators ex with ex +ex operator+(ex const & lh, ex const & rh); +ex operator-(ex const & lh, ex const & rh); +ex operator*(ex const & lh, ex const & rh); +ex operator/(ex const & lh, ex const & rh); +ex operator%(ex const & lh, ex const & rh); // non-commutative multiplication + +/* + +// binary arithmetic operators ex with numeric +ex operator+(ex const & lh, numeric const & rh); +ex operator-(ex const & lh, numeric const & rh); +ex operator*(ex const & lh, numeric const & rh); +ex operator/(ex const & lh, numeric const & rh); +ex operator%(ex const & lh, numeric const & rh); // non-commutative multiplication + +// binary arithmetic operators numeric with ex +ex operator+(numeric const & lh, ex const & rh); +ex operator-(numeric const & lh, ex const & rh); +ex operator*(numeric const & lh, ex const & rh); +ex operator/(numeric const & lh, ex const & rh); +ex operator%(numeric const & lh, ex const & rh); // non-commutative multiplication + +*/ + +// binary arithmetic operators numeric with numeric +numeric operator+(numeric const & lh, numeric const & rh); +numeric operator-(numeric const & lh, numeric const & rh); +numeric operator*(numeric const & lh, numeric const & rh); +numeric operator/(numeric const & lh, numeric const & rh); + +// binary arithmetic assignment operators with ex +ex const & operator+=(ex & lh, ex const & rh); +ex const & operator-=(ex & lh, ex const & rh); +ex const & operator*=(ex & lh, ex const & rh); +ex const & operator/=(ex & lh, ex const & rh); +ex const & operator%=(ex & lh, ex const & rh); // non-commutative multiplication + +/* + +// binary arithmetic assignment operators with numeric +ex const & operator+=(ex & lh, numeric const & rh); +ex const & operator-=(ex & lh, numeric const & rh); +ex const & operator*=(ex & lh, numeric const & rh); +ex const & operator/=(ex & lh, numeric const & rh); +ex const & operator%=(ex & lh, numeric const & rh); // non-commutative multiplication + +*/ + +// binary arithmetic assignment operators with numeric +numeric const & operator+=(numeric & lh, numeric const & rh); +numeric const & operator-=(numeric & lh, numeric const & rh); +numeric const & operator*=(numeric & lh, numeric const & rh); +numeric const & operator/=(numeric & lh, numeric const & rh); + +// unary operators +ex operator+(ex const & lh); +ex operator-(ex const & lh); + +numeric operator+(numeric const & lh); +numeric operator-(numeric const & lh); + +// binary relational operators ex with ex +relational operator==(ex const & lh, ex const & rh); +relational operator!=(ex const & lh, ex const & rh); +relational operator<(ex const & lh, ex const & rh); +relational operator<=(ex const & lh, ex const & rh); +relational operator>(ex const & lh, ex const & rh); +relational operator>=(ex const & lh, ex const & rh); + +/* + +// binary relational operators ex with numeric +relational operator==(ex const & lh, numeric const & rh); +relational operator!=(ex const & lh, numeric const & rh); +relational operator<(ex const & lh, numeric const & rh); +relational operator<=(ex const & lh, numeric const & rh); +relational operator>(ex const & lh, numeric const & rh); +relational operator>=(ex const & lh, numeric const & rh); + +// binary relational operators numeric with ex +relational operator==(numeric const & lh, ex const & rh); +relational operator!=(numeric const & lh, ex const & rh); +relational operator<(numeric const & lh, ex const & rh); +relational operator<=(numeric const & lh, ex const & rh); +relational operator>(numeric const & lh, ex const & rh); +relational operator>=(numeric const & lh, ex const & rh); + +*/ + +// input/output stream operators +ostream & operator<<(ostream & os, ex const & e); +istream & operator>>(istream & is, ex & e); + +#endif // ndef _OPERATORS_H_ + diff --git a/ginac/power.cpp b/ginac/power.cpp new file mode 100644 index 00000000..f0b5c5ad --- /dev/null +++ b/ginac/power.cpp @@ -0,0 +1,695 @@ +/** @file power.cpp + * + * Implementation of GiNaC's symbolic exponentiation (basis^exponent). */ + +#include +#include +#include + +#include "ginac.h" + +typedef vector 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(*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(ebasis.bp); + } + if (is_exactly_of_type(*eexponent.bp,numeric)) { + exponent_is_numerical=1; + num_exponent=static_cast(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(const_cast(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; lsetflag(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; isetflag(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(*basis.bp); + + splitseq=addref.seq; + splitseq.pop_back(); + ex first_operands=add(splitseq); + ex last_operand=addref.recombine_pair_to_ex(*(addref.seq.end()-1)); + + int n=exponent.to_int(); + for (int k=0; k<=n; k++) { + distrseq.push_back(binomial(n,k)*power(first_operands,numeric(k))* + power(last_operand,numeric(n-k))); + } + return ex((new add(distrseq))->setflag(status_flags::sub_expanded | + status_flags::expanded | + status_flags::dynallocated )). + expand(options); +} +*/ + +/* +ex power::expand_noncommutative(ex const & basis, numeric const & exponent, + unsigned options) const +{ + ex rest_power=ex(power(basis,exponent.add(numMINUSONE()))). + expand(options | expand_options::internal_do_not_expand_power_operands); + + return ex(mul(rest_power,basis),0). + expand(options | expand_options::internal_do_not_expand_mul_operands); +} +*/ + +////////// +// static member variables +////////// + +// protected + +unsigned power::precedence=60; + +////////// +// global constants +////////// + +const power some_power; +type_info const & typeid_power=typeid(some_power); diff --git a/ginac/power.h b/ginac/power.h new file mode 100644 index 00000000..ed9c1467 --- /dev/null +++ b/ginac/power.h @@ -0,0 +1,103 @@ +/** @file power.h + * + * Interface to GiNaC's symbolic exponentiation (basis^exponent). */ + +#ifndef _POWER_H_ +#define _POWER_H_ + +class power; +class numeric; +class add; + +/** This class holds a two-component object, a basis and and exponent + * representing exponentiation. */ +class power : public basic +{ + friend class mul; + +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers +public: + power(); + ~power(); + power(power const & other); + power const & operator=(power const & other); +protected: + void copy(power const & other); + void destroy(bool call_parent); + + // other constructors +public: + power(ex const & lh, ex const & rh); + power(ex const & lh, numeric const & rh); + + // functions overriding virtual functions from bases classes +public: + basic * duplicate() const; + void printraw(ostream & os) const; + void printtree(ostream & os, unsigned indent) const; + void print(ostream & os, unsigned upper_precedence=0) const; + void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const; + bool info(unsigned inf) const; + int nops() const; + ex & let_op(int const i); + int degree(symbol const & s) const; + int ldegree(symbol const & s) const; + ex coeff(symbol const & s, int const n=1) const; + ex eval(int level=0) const; + ex evalf(int level=0) const; + ex diff(symbol const & s) const; + ex series(symbol const & s, ex const & point, int order) const; + ex subs(lst const & ls, lst const & lr) const; + ex normal(lst &sym_lst, lst &repl_lst, int level=0) const; + ex simplify_ncmul(exvector const & v) const; +protected: + int compare_same_type(basic const & other) const; + unsigned return_type(void) const; + unsigned return_type_tinfo(void) const; + ex expand(unsigned options=0) const; + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class +protected: + ex expand_add(add const & a, int const n) const; + ex expand_add_2(add const & a) const; + ex expand_mul(mul const & m, numeric const & n) const; + //ex expand_commutative_3(ex const & basis, numeric const & exponent, + // unsigned options) const; + // ex expand_noncommutative(ex const & basis, numeric const & exponent, unsigned options) const; + +// member variables + +protected: + ex basis; + ex exponent; + static unsigned precedence; +}; + +// global constants + +extern const power some_power; +extern type_info const & typeid_power; + +#define ex_to_power(X) static_cast(*(X).bp) + +// wrapper functions + +/** Symbolic exponentiation. Returns a power-object as a new expression. + * + * @param b the basis expression + * @param e the exponent expression */ +inline ex pow(ex const & b, ex const & e) +{ return power(b,e); } + +/** Square root expression. Returns a power-object with exponent 1/2 as a new + * expression. */ +inline ex sqrt(ex const & a) +{ return power(a,exHALF()); } + +#endif // ndef _POWER_H_ + diff --git a/ginac/print.cpp b/ginac/print.cpp new file mode 100644 index 00000000..6cfd0a1f --- /dev/null +++ b/ginac/print.cpp @@ -0,0 +1,287 @@ +/** @file print.cpp + * + * The methods .print() are responsible for the nice default-output of + * objects. All related helper-functions go in here as well. */ + +#include + +#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 + +#include "ginac.h" + +/** Print expression as a C++ statement. The output looks like + * " = ;". 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(*basis.bp), exp); + os << ")"; + + // ^-1 is printed as "1.0/" 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/" + if (it == seq.begin() && ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(numZERO()) < 0) { + if (type == csrc_types::ctype_cl_N) + os << "recip("; + else + os << "1.0/"; + } + + // If the exponent is 1 or -1, it is left out + if (it->coeff.compare(exONE()) == 0 || it->coeff.compare(numMINUSONE()) == 0) + it->rest.bp->printcsrc(os, type, precedence); + else + // outer parens around ex needed for broken gcc-2.95 parser: + (ex(power(it->rest, abs(ex_to_numeric(it->coeff))))).bp->printcsrc(os, type, upper_precedence); + + // Separator is "/" for negative integer powers, "*" otherwise + it++; + if (it != itend) { + if (ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(numZERO()) < 0) + os << "/"; + else + os << "*"; + } + } + if (precedence <= upper_precedence) + os << ")"; +} + +void ncmul::printcsrc(ostream & os, unsigned upper_precedence) const +{ + debugmsg("ncmul print csrc",LOGLEVEL_PRINT); + exvector::const_iterator it; + exvector::const_iterator itend = seq.end()-1; + os << "ncmul("; + for (it=seq.begin(); it!=itend; ++it) { + (*it).bp->printcsrc(os,precedence); + os << ","; + } + (*it).bp->printcsrc(os,precedence); + os << ")"; +} + +void relational::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const +{ + debugmsg("relational print csrc", LOGLEVEL_PRINT); + if (precedence<=upper_precedence) + os << "("; + + // Print left-hand expression + lh.bp->printcsrc(os, type, precedence); + + // Print relational operator + switch (o) { + case equal: + os << "=="; + break; + case not_equal: + os << "!="; + break; + case less: + os << "<"; + break; + case less_or_equal: + os << "<="; + break; + case greater: + os << ">"; + break; + case greater_or_equal: + os << ">="; + break; + default: + os << "(INVALID RELATIONAL OPERATOR)"; + break; + } + + // Print right-hand operator + rh.bp->printcsrc(os, type, precedence); + + if (precedence <= upper_precedence) + os << ")"; +} diff --git a/ginac/printraw.cpp b/ginac/printraw.cpp new file mode 100644 index 00000000..8315c818 --- /dev/null +++ b/ginac/printraw.cpp @@ -0,0 +1,190 @@ +/** @file printraw.cpp + * + * print in ugly raw format, so brave developers can have a look at the + * underlying structure. */ + +/* We are cheating here, because we don't want to include the underlying + * bignum package's headers again, so in this file we omit the definition of + * void numeric::printraw(ostream & os) const; */ + +#include + +#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 +#include + +#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; i0) { + 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_fill0) fact *= k; + double prob=pow(lambda,k)/fact*exp(-lambda); + cum_prob += prob; + os << string(indent+delta_indent,' ') << "bins with " << k << " entries: " + << int(1000.0*count[k]/hashtabsize)/10.0 << "% (expected: " + << int(prob*1000)/10.0 << ")" << endl; + } + os << string(indent+delta_indent,' ') << "bins with more entries: " + << int(1000.0*count[MAXCOUNT]/hashtabsize)/10.0 << "% (expected: " + << int((1-cum_prob)*1000)/10.0 << ")" << endl; + + os << string(indent+delta_indent,' ') << "variance: " + << 1.0/hashtabsize*cum_fill_sq-(1.0/hashtabsize*cum_fill)*(1.0/hashtabsize*cum_fill) + << endl; + os << string(indent+delta_indent,' ') << "average fill: " + << (1.0*cum_fill)/hashtabsize + << " (should be equal to " << (1.0*seq.size())/hashtabsize << ")" << endl; +#endif // def EXPAIRSEQ_USE_HASHTAB +} + diff --git a/ginac/relational.cpp b/ginac/relational.cpp new file mode 100644 index 00000000..252d8b35 --- /dev/null +++ b/ginac/relational.cpp @@ -0,0 +1,244 @@ +/** @file relational.cpp + * + * Implementation of relations between expressions */ + +#include + +#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(const_cast(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 + +relational::operator bool() const +{ + // please note that (a=b) == true + // a false result means the comparison is either false or undecidable + // (except for !=, where true means unequal or undecidable) + ex df=lh-rh; + if (!is_ex_exactly_of_type(df,numeric)) { + return o==not_equal ? true : false; // cannot decide on non-numerical results + } + int cmpval=ex_to_numeric(df).compare(numZERO()); + switch (o) { + case equal: + return cmpval==0; + break; + case not_equal: + return cmpval!=0; + break; + case less: + return cmpval<0; + break; + case less_or_equal: + return cmpval<=0; + break; + case greater: + return cmpval>0; + break; + case greater_or_equal: + return cmpval>=0; + break; + default: + throw(std::logic_error("invalid relational operator")); + } + return 0; +} + +////////// +// static member variables +////////// + +// protected + +unsigned relational::precedence=20; + +////////// +// global constants +////////// + +const relational some_relational; +type_info const & typeid_relational=typeid(some_relational); + diff --git a/ginac/relational.h b/ginac/relational.h new file mode 100644 index 00000000..34c592cf --- /dev/null +++ b/ginac/relational.h @@ -0,0 +1,85 @@ +/** @file relational.h + * + * Interface to relations between expressions. */ + +#ifndef _RELATIONAL_H_ +#define _RELATIONAL_H_ + +class relational; + +#include "basic.h" + +/** This class holds a relation consisting of two expressions and a logical + * relation between them. */ +class relational : public basic +{ + +// types +public: + enum operators { equal, + not_equal, + less, + less_or_equal, + greater, + greater_or_equal + }; + +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers +public: + relational(); + ~relational(); + relational(relational const & other); + relational const & operator=(relational const & other); +protected: + void copy(relational const & other); + void destroy(bool call_parent); + + // other constructors +public: + relational(ex const & lhs, ex const & rhs, operators oper=equal); + + // functions overriding virtual functions from bases classes +public: + basic * duplicate() const; + void printraw(ostream & os) const; + void print(ostream & os, unsigned upper_precedence=0) const; + void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const; + bool info(unsigned inf) const; + int nops() const; + ex & let_op(int const i); + ex eval(int level=0) const; + ex evalf(int level=0) const; + ex simplify_ncmul(exvector const & v) const; +protected: + int compare_same_type(basic const & other) const; + unsigned return_type(void) const; + unsigned return_type_tinfo(void) const; + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class +public: + operator bool(void) const; + +// member variables + +protected: + ex lh; + ex rh; + operators o; + static unsigned precedence; +}; + +// global constants + +extern const relational some_relational; +extern type_info const & typeid_relational; + +#define ex_to_relational(X) static_cast(*(X).bp) + +#endif // ndef _RELATIONAL_H_ + + diff --git a/ginac/series.cpp b/ginac/series.cpp new file mode 100644 index 00000000..9daf656b --- /dev/null +++ b/ginac/series.cpp @@ -0,0 +1,610 @@ +/** @file series.cpp + * + * Implementation of class for extended truncated power-series and + * methods for series expansion. */ + +#include "ginac.h" + + +/* + * Default constructor, destructor, copy constructor, assignment operator and helpers + */ + +series::series() : basic(TINFO_SERIES) +{ + debugmsg("series default constructor", LOGLEVEL_CONSTRUCT); +} + +series::~series() +{ + debugmsg("series destructor", LOGLEVEL_DESTRUCT); + destroy(false); +} + +series::series(series const &other) +{ + debugmsg("series copy constructor", LOGLEVEL_CONSTRUCT); + copy(other); +} + +series const &series::operator=(series const & other) +{ + debugmsg("series operator=", LOGLEVEL_ASSIGNMENT); + if (this != &other) { + destroy(true); + copy(other); + } + return *this; +} + +void series::copy(series const &other) +{ + inherited::copy(other); + seq = other.seq; + var = other.var; + point = other.point; +} + +void series::destroy(bool call_parent) +{ + if (call_parent) + inherited::destroy(call_parent); +} + + +/* + * Other constructors + */ + +/** Construct series from a vector of coefficients and powers. + * expair.rest holds the coefficient, expair.coeff holds the power. + * The powers must be integers (positive or negative) and in ascending order; + * the last coefficient can be Order(exONE()) to represent a truncated, + * non-terminating series. + * + * @param var_ series variable (must hold a symbol) + * @param point_ expansion point + * @param ops_ vector of {coefficient, power} pairs (coefficient must not be zero) + * @return newly constructed series */ +series::series(ex const &var_, ex const &point_, epvector const &ops_) + : basic(TINFO_SERIES), seq(ops_), var(var_), point(point_) +{ + debugmsg("series constructor from ex,ex,epvector", LOGLEVEL_CONSTRUCT); + ASSERT(is_ex_exactly_of_type(var_, symbol)); +} + + +/* + * Functions overriding virtual functions from base classes + */ + +basic *series::duplicate() const +{ + debugmsg("series duplicate", LOGLEVEL_DUPLICATE); + return new series(*this); +} + +// Highest degree of variable +int series::degree(symbol const &s) const +{ + if (var == s) { + // Return last exponent + if (seq.size()) + return ex_to_numeric((*(seq.end() - 1)).coeff).to_int(); + else + return 0; + } else { + epvector::const_iterator it = seq.begin(), itend = seq.end(); + if (it == itend) + return 0; + int max_pow = INT_MIN; + while (it != itend) { + int pow = it->rest.degree(s); + if (pow > max_pow) + max_pow = pow; + it++; + } + return max_pow; + } +} + +// Lowest degree of variable +int series::ldegree(symbol const &s) const +{ + if (var == s) { + // Return first exponent + if (seq.size()) + return ex_to_numeric((*(seq.begin())).coeff).to_int(); + else + return 0; + } else { + epvector::const_iterator it = seq.begin(), itend = seq.end(); + if (it == itend) + return 0; + int min_pow = INT_MAX; + while (it != itend) { + int pow = it->rest.ldegree(s); + if (pow < min_pow) + min_pow = pow; + it++; + } + return min_pow; + } +} + +// Coefficient of variable +ex series::coeff(symbol const &s, int n) const +{ + if (var == s) { + epvector::const_iterator it = seq.begin(), itend = seq.end(); + while (it != itend) { + int pow = ex_to_numeric(it->coeff).to_int(); + if (pow == n) + return it->rest; + if (pow > n) + return exZERO(); + it++; + } + return exZERO(); + } else + return convert_to_poly().coeff(s, n); +} + +ex series::eval(int level) const +{ + if (level == 1) + return this->hold(); + + // Construct a new series with evaluated coefficients + epvector new_seq; + new_seq.reserve(seq.size()); + epvector::const_iterator it = seq.begin(), itend = seq.end(); + while (it != itend) { + new_seq.push_back(expair(it->rest.eval(level-1), it->coeff)); + it++; + } + return (new series(var, point, new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated); +} + +ex series::evalf(int level) const +{ + return convert_to_poly().evalf(level); +} + + +/* + * Construct expression (polynomial) out of series + */ + +/** Convert a series object to an ordinary polynomial. + * + * @param no_order flag: discard higher order terms */ +ex series::convert_to_poly(bool no_order) const +{ + ex e; + epvector::const_iterator it = seq.begin(), itend = seq.end(); + + while (it != itend) { + if (is_order_function(it->rest)) { + if (!no_order) + e += Order(power(var - point, it->coeff)); + } else + e += it->rest * power(var - point, it->coeff); + it++; + } + return e; +} + + +/* + * Implementation of series expansion + */ + +/** Default implementation of ex::series(). This performs Taylor expansion. + * @see ex::series */ +ex basic::series(symbol const & s, ex const & point, int order) const +{ + epvector seq; + numeric fac(1); + ex deriv = *this; + ex coeff = deriv.subs(s == point); + if (!coeff.is_zero()) + seq.push_back(expair(coeff, numeric(0))); + + int n; + for (n=1; nrest, 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(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(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; iseries(s, point, order); +} + + +// Global constants +const series some_series; +type_info const & typeid_series = typeid(some_series); diff --git a/ginac/series.h b/ginac/series.h new file mode 100644 index 00000000..89b91267 --- /dev/null +++ b/ginac/series.h @@ -0,0 +1,77 @@ +/** @file series.h + * + * Interface to class for extended truncated power series. */ + +#ifndef _SERIES_H_ +#define _SERIES_H_ + +#include "basic.h" +#include "ex.h" +#include "expairseq.h" +#include "symbol.h" + + +/** This class holds a extended truncated power series (positive and negative + * integer powers). It consists of expression coefficients (only non-zero + * coefficients are stored), an expansion variable and an expansion point. + * Other classes must provide members to convert into this type. */ +class series : public basic +{ + typedef basic inherited; + + // default constructor, destructor, copy constructor, assignment operator and helpers +public: + series(); + ~series(); + series(series const &other); + series const &operator=(series const &other); +protected: + void copy(series const &other); + void destroy(bool call_parent); + + // other constructors +public: + series(ex const &var_, ex const &point_, epvector const &ops_); + + // functions overriding virtual functions from base classes +public: + basic *duplicate() const; + void printraw(ostream &os) const; + void print(ostream &os, unsigned upper_precedence=0) const; + int degree(symbol const &s) const; + int ldegree(symbol const &s) const; + ex coeff(symbol const &s, int const n=1) const; + ex eval(int level=0) const; + ex evalf(int level=0) const; + ex diff(symbol const & s) const; + ex normal(lst &sym_lst, lst &repl_lst, int level=0) const; + + // non-virtual functions in this class +public: + ex convert_to_poly(bool no_order = false) const; + bool is_compatible_to(const series &other) const {return var.compare(other.var) == 0 && point.compare(other.point) == 0;} + bool is_zero(void) const {return seq.size() == 0;} + ex add_series(const series &other) const; + ex mul_const(const numeric &other) const; + ex mul_series(const series &other) const; + ex power_const(const numeric &p, int deg) const; + +protected: + /** Vector of {coefficient, power} pairs */ + epvector seq; + + /** Series variable (holds a symbol) */ + ex var; + + /** Expansion point */ + ex point; +}; + +// global constants +extern const series some_series; +extern type_info const & typeid_series; + +#define ex_to_series(X) (static_cast(*(X).bp)) +#define series_to_poly(X) (static_cast(*(X).bp).convert_to_poly(true)) + +#endif diff --git a/ginac/simp_lor.cpp b/ginac/simp_lor.cpp new file mode 100644 index 00000000..32d05b0c --- /dev/null +++ b/ginac/simp_lor.cpp @@ -0,0 +1,493 @@ +/** @file simp_lor.cpp + * + * Implementation of GiNaC's simp_lor objects. + * No real implementation yet, to be done. */ + +#include +#include +#include +#include +#include +#include + +#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(&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(&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; i0) { + reg(v2,v1,sp); + return; + } + spm[make_key(v1,v2)]=sp; +} + +bool scalar_products::is_defined(simp_lor const & v1, simp_lor const & v2) const +{ + if (v1.compare_same_type(v2)>0) { + return is_defined(v2,v1); + } + return spm.find(make_key(v1,v2))!=spm.end(); +} + +ex scalar_products::evaluate(simp_lor const & v1, simp_lor const & v2) const +{ + if (v1.compare_same_type(v2)>0) { + return evaluate(v2,v1); + } + return spm.find(make_key(v1,v2))->second; +} + +void scalar_products::debugprint(void) const +{ + cerr << "map size=" << spm.size() << endl; + for (spmap::const_iterator cit=spm.begin(); cit!=spm.end(); ++cit) { + spmapkey const & k=(*cit).first; + cerr << "item key=((" << k.first.first + << "," << k.first.second << "),"; + k.second.printraw(cerr); + cerr << ") value=" << (*cit).second << endl; + } +} + +spmapkey scalar_products::make_key(simp_lor const & v1, simp_lor const & v2) +{ + ASSERT(v1.type==simp_lor::simp_lor_vec); + ASSERT(v2.type==simp_lor::simp_lor_vec); + lorentzidx anon=ex_to_lorentzidx(v1.seq[0]).create_anonymous_representative(); + ASSERT(anon.is_equal_same_type(ex_to_lorentzidx(v2.seq[0]).create_anonymous_representative())); + return spmapkey(strstrpair(v1.name,v2.name),anon); +} + + + diff --git a/ginac/simp_lor.h b/ginac/simp_lor.h new file mode 100644 index 00000000..8efe1b3d --- /dev/null +++ b/ginac/simp_lor.h @@ -0,0 +1,152 @@ +/** @file simp_lor.h + * + * Interface to GiNaC's simp_lor objects. */ + +#ifndef _SIMP_LOR_H_ +#define _SIMP_LOR_H_ + +#include +#include +#include +#include +#include + +class simp_lor; + +#include "indexed.h" +#include "lorentzidx.h" + +typedef pair strstrpair; +typedef pair 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 & structure::registered_structures(void) +{ + static vector * rs=new vector; + return *rs; +} + +// public + +unsigned structure::register_new(char const * nm) +{ + registered_structure_info rsi={nm}; + registered_structures().push_back(rsi); + return registered_structures().size()-1; +} + +////////// +// static member variables +////////// + +// none + +////////// +// global constants +////////// + +const structure some_structure; +type_info const & typeid_structure=typeid(some_structure); + diff --git a/ginac/structure.h b/ginac/structure.h new file mode 100644 index 00000000..b1c8bef7 --- /dev/null +++ b/ginac/structure.h @@ -0,0 +1,70 @@ +/** @file structure.h + * + * Interface to 'abstract' class structure. */ + +#ifndef _STRUCTURE_H_ +#define _STRUCTURE_H_ + +class structure; + +#include "basic.h" + +struct registered_structure_info { + char const * name; +}; + +/** The class structure is used to implement user defined classes + with named members which behave similar to ordinary C structs. + structure is an 'abstract' base class (it is possible but not + meaningful to make instances), the user defined structures + will be create by the perl script structure.pl */ + +class structure : public basic +{ +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers +public: + structure(); + ~structure(); + structure(structure const & other); + structure const & operator=(structure const & other); +protected: + void copy(structure const & other); + void destroy(bool call_parent); + + // other constructors + // none + + // functions overriding virtual functions from bases classes +public: + basic * duplicate() const; + void printraw(ostream & os) const; + void print(ostream & os, unsigned upper_precedence=0) const; + void printtree(ostream & os, unsigned indent) const; + void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const; +protected: + int compare_same_type(basic const & other) const; + bool is_equal_same_type(basic const & other) const; + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class +protected: + static vector & registered_structures(void); +public: + static unsigned register_new(char const * nm); + +// member variables +// none + +}; + +// global constants + +extern const structure some_structure; +extern type_info const & typeid_structure; + +#endif // ndef _STRUCTURE_H_ + diff --git a/ginac/structure.pl b/ginac/structure.pl new file mode 100755 index 00000000..725b03a5 --- /dev/null +++ b/ginac/structure.pl @@ -0,0 +1,483 @@ +#!/usr/bin/perl -w + +$input_structure=''; +$original_input_structure=''; +while (<>) { + $input_structure .= '// '.$_; + $original_input_structure .= $_; +} + +$original_input_structure =~ tr/ \t\n\r\f/ /; +$original_input_structure =~ tr/ //s; + +if ($original_input_structure =~ /^struct (\w+) ?\{ ?(.*)\}\;? ?$/) { + $STRUCTURE=$1; + $decl=$2; +} else { + die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $original_input_structure"; +} + +# split off a part 'type var[,var...];' with a possible C-comment '/* ... */' +while ($decl =~ /^ ?(\w+) ([\w \,]+)\; ?((\/\*.*?\*\/)?)(.*)$/) { + $type=$1; + $member=$2; + $comment=$3; + $decl=$5; + while ($member =~ /^(\w+) ?\, ?(.*)$/) { + push @TYPES,$type; + push @MEMBERS,$1; + push @COMMENTS,$comment; + if ($comment ne '') { + $comment='/* see above */'; + } + $member=$2; + } + if ($member !~ /^\w$/) { + die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $input_structure"; + } + push @TYPES,$type; + push @MEMBERS,$member; + push @COMMENTS,$comment; +} + +if ($decl !~ /^ ?$/) { + die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $input_structure"; +} + +#$STRUCTURE='teststruct'; +$STRUCTURE_UC=uc(${STRUCTURE}); +#@TYPES=('ex','ex','ex'); +#@MEMBERS=('q10','q20','q21'); + +sub generate { + my ($template,$conj)=@_; + my ($res,$N); + + $res=''; + for ($N=1; $N<=$#MEMBERS+1; $N++) { + $TYPE=$TYPES[$N-1]; + $MEMBER=$MEMBERS[$N-1]; + $COMMENT=$COMMENTS[$N-1]; + $res .= eval('"' . $template . '"'); + $TYPE=''; # to avoid main::TYPE used only once warning + $MEMBER=''; # same as above + $COMMENT=''; # same as above + if ($N!=$#MEMBERS+1) { + $res .= $conj; + } + } + return $res; +} + +$number_of_members=$#MEMBERS+1; +$constructor_arglist=generate('ex tmp_${MEMBER}',', '); +$member_access_functions=generate(' ex const & ${MEMBER}(void) { return m_${MEMBER}; }',"\n"); +$op_access_indices_decl=generate(' static unsigned op_${MEMBER};',"\n"); +$op_access_indices_def=generate('unsigned ${STRUCTURE}::op_${MEMBER}=${N}-1;',"\n"); +$members=generate(' ex m_${MEMBER}; ${COMMENT}',"\n"); +$copy_statements=generate(' m_${MEMBER}=other.m_${MEMBER};',"\n"); +$constructor_statements=generate('m_${MEMBER}(tmp_${MEMBER})',', '); +$let_op_statements=generate( +' case ${N}-1:'."\n". +' return m_${MEMBER};'."\n". +' break;', +"\n"); +$temporary_arglist=generate('tmp_${MEMBER}',', '); +$expand_statements=generate(' ex tmp_${MEMBER}=m_${MEMBER}.expand(options);',"\n"); +$has_statements=generate(' if (m_${MEMBER}.has(other)) return true;',"\n"); +$eval_statements=generate( +' ex tmp_${MEMBER}=m_${MEMBER}.eval(level-1);'."\n". +' all_are_trivially_equal = all_are_trivially_equal &&'."\n". +' are_ex_trivially_equal(tmp_${MEMBER},m_${MEMBER});', +"\n"); +$evalf_statements=generate( +' ex tmp_${MEMBER}=m_${MEMBER}.evalf(level-1);'."\n". +' all_are_trivially_equal = all_are_trivially_equal &&'."\n". +' are_ex_trivially_equal(tmp_${MEMBER},m_${MEMBER});', +"\n"); +$normal_statements=generate( +' ex tmp_${MEMBER}=m_${MEMBER}.normal(level-1);'."\n". +' all_are_trivially_equal = all_are_trivially_equal &&'."\n". +' are_ex_trivially_equal(tmp_${MEMBER},m_${MEMBER});', +"\n"); +$diff_statements=generate(' ex tmp_${MEMBER}=m_${MEMBER}.diff(s);',"\n"); +$subs_statements=generate( +' ex tmp_${MEMBER}=m_${MEMBER}.subs(ls,lr);'."\n". +' all_are_trivially_equal = all_are_trivially_equal &&'."\n". +' are_ex_trivially_equal(tmp_${MEMBER},m_${MEMBER});', +"\n"); +$compare_statements=generate( +' cmpval=m_${MEMBER}.compare(o.m_${MEMBER});'."\n". +' if (cmpval!=0) return cmpval;', +"\n"); +$is_equal_statements=generate(' if (!m_${MEMBER}.is_equal(o.m_${MEMBER})) return false;',"\n"); +$types_ok_statements=generate( +'#ifndef SKIP_TYPE_CHECK_FOR_${TYPE}'."\n". +' if (!is_ex_exactly_of_type(m_${MEMBER},${TYPE})) return false;'."\n". +'#endif // ndef SKIP_TYPE_CHECK_FOR_${TYPE}',"\n"); + +$interface=< + +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=< + +#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(ihold(); + } + 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(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(other)); +${is_equal_statements} + return true; +} + +unsigned ${STRUCTURE}::return_type(void) const +{ + return return_types::noncommutative_composite; +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +// public + +#define SKIP_TYPE_CHECK_FOR_ex +// this is a hack since there is no meaningful +// is_ex_exactly_of_type(...,ex) macro definition + +bool ${STRUCTURE}::types_ok(void) const +{ +${types_ok_statements} + return true; +} + +////////// +// static member variables +////////// + +${op_access_indices_def} + +////////// +// global constants +////////// + +const ${STRUCTURE} some_${STRUCTURE}; +type_info const & typeid_${STRUCTURE}=typeid(some_${STRUCTURE}); +const unsigned tinfo_${STRUCTURE}=structure::register_new("${STRUCTURE}"); + +END_OF_IMPLEMENTATION + +print "Creating interface file ${STRUCTURE}.h..."; +open OUT,">${STRUCTURE}.h" or die "cannot open ${STRUCTURE}.h"; +print OUT $interface; +close OUT; +print "ok.\n"; + +print "Creating implementation file ${STRUCTURE}.cpp..."; +open OUT,">${STRUCTURE}.cpp" or die "cannot open ${STRUCTURE}.cpp"; +print OUT $implementation; +close OUT; +print "ok.\n"; + +print "done.\n"; diff --git a/ginac/symbol.cpp b/ginac/symbol.cpp new file mode 100644 index 00000000..6822dc49 --- /dev/null +++ b/ginac/symbol.cpp @@ -0,0 +1,259 @@ +/** @file symbol.cpp + * + * Implementation of GiNaC's symbolic objects. */ + +#include +#include + +#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(&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(&other); + return serial==o->serial; +} + +unsigned symbol::return_type(void) const +{ + return return_types::commutative; +} + +unsigned symbol::return_type_tinfo(void) const +{ + return tinfo_key; +} + +unsigned symbol::calchash(void) const +{ + // return golden_ratio_hash(tinfo()) ^ serial; + hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555555U ^ serial)); + setflag(status_flags::hash_calculated); + return hashvalue; +} + +////////// +// virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +// public + +void symbol::assign(ex const & value) +{ + asexinfop->is_assigned=1; + asexinfop->assigned_expression=value; + clearflag(status_flags::evaluated); +} + +void symbol::unassign(void) +{ + if (asexinfop->is_assigned) { + asexinfop->is_assigned=0; + asexinfop->assigned_expression=exZERO(); + } + setflag(status_flags::evaluated); +} + +// private + +string & symbol::autoname_prefix(void) +{ + static string * s=new string("symbol"); + return *s; +} + +////////// +// static member variables +////////// + +// private + +unsigned symbol::next_serial=0; + +// string const symbol::autoname_prefix="symbol"; + +////////// +// global constants +////////// + +const symbol some_symbol; +type_info const & typeid_symbol=typeid(some_symbol); + +////////// +// subclass assigned_ex_info +////////// + +/** Default ctor. Defaults to unassigned. */ +symbol::assigned_ex_info::assigned_ex_info(void) : is_assigned(0), refcount(1) +{ +} diff --git a/ginac/symbol.h b/ginac/symbol.h new file mode 100644 index 00000000..a10998ec --- /dev/null +++ b/ginac/symbol.h @@ -0,0 +1,111 @@ +/** @file symbol.h + * + * Interface to GiNaC's symbolic objects. */ + +#ifndef _SYMBOL_H_ +#define _SYMBOL_H_ + +#include + +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(*(X).bp) + +// wrapper functions around member functions +inline void unassign(symbol & symarg) +{ return symarg.unassign(); } + +inline int degree(symbol const & a, symbol const & s) +{ return a.degree(s); } + +inline int ldegree(symbol const & a, symbol const & s) +{ return a.ldegree(s); } + +#endif // ndef _SYMBOL_H_ diff --git a/ginac/tinfos.h b/ginac/tinfos.h new file mode 100644 index 00000000..de799aa9 --- /dev/null +++ b/ginac/tinfos.h @@ -0,0 +1,51 @@ +/** @file tinfos.h + * + * Values for a do-it-yourself typeinfo scheme. */ + +#ifndef _TINFOS_H_ +#define _TINFOS_H_ + +#define TINFO_BASIC 0x00000001U + +#define TINFO_EXPAIRSEQ 0x00010001U +#define TINFO_ADD 0x00011001U +#define TINFO_MUL 0x00011002U + +#define TINFO_SYMBOL 0x00020001U +#define TINFO_CONSTANT 0x00021001U + +#define TINFO_EXPRSEQ 0x00030001U +#define TINFO_FUNCTION 0x00031001U +#define TINFO_NCMUL 0x00031002U +// #define TINFO_NFUNCTION 0x00031003U + +#define TINFO_LST 0x00040001U + +#define TINFO_MATRIX 0x00050001U + +#define TINFO_POWER 0x00060001U + +#define TINFO_RELATIONAL 0x00070001U + +#define TINFO_FAIL 0x00080001U + +#define TINFO_NUMERIC 0x00090001U + +#define TINFO_SERIES 0x000a0001U + +#define TINFO_INDEXED 0x000b0001U +#define TINFO_ALGEBRA 0x000b1001U +#define TINFO_CLIFFORD 0x000b1101U +#define TINFO_COLOR 0x000b1201U +#define TINFO_ISOSPIN 0x000b1301U +#define TINFO_SIMP_LOR 0x000b1401U + +#define TINFO_STRUCTURE 0x000c0001U +// reserved up to 0x000cffffU +// for user defined structures + +#define TINFO_IDX 0x000d0001U +#define TINFO_COLORIDX 0x000d1001U +#define TINFO_LORENTZIDX 0x000d1002U + +#endif // ndef _TINFOS_H_ diff --git a/ginac/utils.cpp b/ginac/utils.cpp new file mode 100644 index 00000000..ae0160d4 --- /dev/null +++ b/ginac/utils.cpp @@ -0,0 +1,98 @@ +/** @file utils.cpp + * + * Implementation of several small and furry utilities. */ + +unsigned log2(unsigned n) +{ + unsigned k; + for (k = 0; n > 1; n >>= 1) ++k; + return k; +} + +int compare_pointers(void const * a, void const * b) +{ + if (ab) { + return 1; + } + return 0; +} + +// comment skeletton for header files + + +// member functions + + // default constructor, destructor, copy constructor assignment operator and helpers + // none + + // other constructors + // none + + // functions overriding virtual functions from bases classes + // none + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class + // none + +// member variables +// none + + + +// comment skeletton for implementation files + + +////////// +// default constructor, destructor, copy constructor assignment operator and helpers +////////// + +// public +// protected + +////////// +// other constructors +////////// + +// public +// none + +////////// +// functions overriding virtual functions from bases classes +////////// + +// public +// protected +// none + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// public +// protected +// none + +////////// +// non-virtual functions in this class +////////// + +// public +// protected +// none + +////////// +// static member variables +////////// + +// protected +// private +// none + + + + diff --git a/ginac/utils.h b/ginac/utils.h new file mode 100644 index 00000000..a19aea47 --- /dev/null +++ b/ginac/utils.h @@ -0,0 +1,75 @@ +/** @file utils.h + * + * Interface to several small and furry utilities. */ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include +#include +#include "config.h" + +template +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(const_cast(EXPRESSION)) + +// modified from stl_algo.h: always do com(*first1,*first2) instead of comp(*first2,*first1) +template +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 +OutputIterator mymerge3(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + InputIterator3 first3, InputIterator3 last3, + OutputIterator result, Compare comp) { + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + *result = *first1; + ++first1; + } + else { + *result = *first2; + ++first2; + } + ++result; + } + + if (first1==last1) { + // list1 empty, copy rest of list2, then list3 + return copy(first3, last3, copy(first2, last2, result)); + } else { + // list2 empty, merge rest of list1 with list3 + return mymerge(first1,last1,first3,last3,result,comp); + } +} + +#endif // ndef _UTILS_H_ diff --git a/ginsh/Makefile.am b/ginsh/Makefile.am new file mode 100644 index 00000000..25a5d8e4 --- /dev/null +++ b/ginsh/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in +bin_PROGRAMS = ginsh +ginsh_SOURCES = ginsh_parser.yy ginsh_lexer.ll ginsh.h +ginsh_LDADD = @LIBOBJS@ ../ginac/libginac.la +man_MANS = ginsh.1 +YFLAGS = -d diff --git a/ginsh/Makefile.in b/ginsh/Makefile.in index fefd5d5a..1ed74437 100644 --- a/ginsh/Makefile.in +++ b/ginsh/Makefile.in @@ -1,88 +1,400 @@ -# 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: diff --git a/ginsh/ginsh.h b/ginsh/ginsh.h index 24f37c00..335e0f1a 100644 --- a/ginsh/ginsh.h +++ b/ginsh/ginsh.h @@ -2,8 +2,8 @@ * ginsh.h - GiNaC Interactive Shell, global definitions */ -#ifndef GINSH_H_ -#define GINSH_H_ +#ifndef GINSH_H +#define GINSH_H // yacc semantic type #define YYSTYPE ex @@ -21,14 +21,9 @@ extern char yytext[]; typedef map 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 diff --git a/ginsh/ginsh.l b/ginsh/ginsh_lexer.ll similarity index 96% rename from ginsh/ginsh.l rename to ginsh/ginsh_lexer.ll index 6f4fb212..b282f836 100644 --- a/ginsh/ginsh.l +++ b/ginsh/ginsh_lexer.ll @@ -12,20 +12,17 @@ %{ #include "config.h" -#if STDC_HEADERS #include -#endif - extern "C" { #include #include } #include -#include - +#include #include "ginsh.h" -#include "y.tab.h" + +#include "ginsh_parser.h" #define YY_INPUT(buf, result, max_size) (result = ginsh_input(buf, max_size)) @@ -157,3 +154,9 @@ static int ginsh_input(char *buf, int max_size) return result; } + +// Scanner terminates on EOF +int yywrap() +{ + return 1; +} diff --git a/ginsh/ginsh.y b/ginsh/ginsh_parser.yy similarity index 99% rename from ginsh/ginsh.y rename to ginsh/ginsh_parser.yy index e0d1de84..6601a2a0 100644 --- a/ginsh/ginsh.y +++ b/ginsh/ginsh_parser.yy @@ -19,22 +19,20 @@ #include #endif -#if STDC_HEADERS #include #include #include -#endif extern "C" { #include #include } + #include #include #include -#include - +#include #include "ginsh.h" // Original readline settings diff --git a/ginsh/strdup.c b/ginsh/strdup.c new file mode 100644 index 00000000..267186d9 --- /dev/null +++ b/ginsh/strdup.c @@ -0,0 +1,10 @@ +/* + * Replacement for strdup() function + */ + +char *strdup(const char *s) +{ + char *n = (char *)malloc(strlen(s) + 1); + strcpy(n, s); + return n; +} diff --git a/ltconfig b/ltconfig new file mode 100755 index 00000000..e69de29b diff --git a/ltmain.sh b/ltmain.sh new file mode 100644 index 00000000..e69de29b diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 00000000..e69de29b -- 2.44.0