]> www.ginac.de Git - ginac.git/commitdiff
[BUGFIX] Fix crash in parser. master
authorRichard Kreckel <kreckel@ginac.de>
Fri, 5 Apr 2024 16:34:48 +0000 (18:34 +0200)
committerRichard Kreckel <kreckel@ginac.de>
Fri, 5 Apr 2024 16:34:48 +0000 (18:34 +0200)
Relying on aligned functions is non-portable.

Reported by Diego Conti <diego.conti@unipi.it>.

291 files changed:
.gitignore [new file with mode: 0644]
AUTHORS
CMakeLists.txt
CVSROOT/checkoutlist [deleted file]
CVSROOT/commitinfo [deleted file]
CVSROOT/config [deleted file]
CVSROOT/cvswrappers [deleted file]
CVSROOT/editinfo [deleted file]
CVSROOT/loginfo [deleted file]
CVSROOT/modules [deleted file]
CVSROOT/notify [deleted file]
CVSROOT/rcsinfo [deleted file]
CVSROOT/taginfo [deleted file]
CVSROOT/verifymsg [deleted file]
ChangeLog
GiNaC.spec.in
INSTALL
INSTALL.CMake
Makefile.am
NEWS
README
acinclude.m4
check/.gitignore [new file with mode: 0644]
check/CMakeLists.txt
check/FILES [new file with mode: 0644]
check/Makefile.am
check/check_cra.cpp [moved from check/exam_cra.cpp with 98% similarity]
check/check_inifcns.cpp
check/check_lsolve.cpp
check/check_matrices.cpp
check/check_mul_info.cpp [deleted file]
check/check_numeric.cpp
check/error_report.h
check/exam_archive.cpp
check/exam_chinrem_gcd.cpp [moved from check/bugme_chinrem_gcd.cpp with 96% similarity]
check/exam_clifford.cpp
check/exam_collect.cpp [new file with mode: 0644]
check/exam_collect_common_factors.cpp [new file with mode: 0644]
check/exam_color.cpp
check/exam_differentiation.cpp
check/exam_factor.cpp
check/exam_function_exvector.cpp [new file with mode: 0644]
check/exam_hashmap.cpp [deleted file]
check/exam_heur_gcd.cpp [moved from check/heur_gcd_bug.cpp with 90% similarity]
check/exam_indexed.cpp
check/exam_inifcns.cpp
check/exam_inifcns_elliptic.cpp [new file with mode: 0644]
check/exam_inifcns_nstdsums.cpp
check/exam_inifcns_nstdsums.h
check/exam_lsolve.cpp
check/exam_match.cpp [moved from check/match_bug.cpp with 93% similarity]
check/exam_matrices.cpp
check/exam_misc.cpp
check/exam_mod_gcd.cpp
check/exam_normalization.cpp
check/exam_numeric.cpp
check/exam_paranoia.cpp
check/exam_parser.cpp [new file with mode: 0644]
check/exam_pgcd.cpp [new file with mode: 0644]
check/exam_polygcd.cpp
check/exam_powerlaws.cpp
check/exam_pseries.cpp
check/exam_real_imag.cpp
check/exam_relational.cpp [new file with mode: 0644]
check/exam_sqrfree.cpp [new file with mode: 0644]
check/exam_structure.cpp
check/factor_univariate_bug.cpp [deleted file]
check/genex.cpp
check/mul_eval_memleak.cpp [deleted file]
check/numeric_archive.cpp [deleted file]
check/parser_bugs.cpp [deleted file]
check/parser_memleak.cpp [deleted file]
check/pgcd_infinite_loop.cpp [deleted file]
check/pgcd_relatively_prime_bug.cpp [deleted file]
check/randomize_serials.cpp
check/test_runner.h
check/time_antipode.cpp
check/time_dennyfliegner.cpp
check/time_fateman_expand.cpp
check/time_gammaseries.cpp
check/time_hashmap.cpp [deleted file]
check/time_lw_A.cpp
check/time_lw_B.cpp
check/time_lw_C.cpp
check/time_lw_D.cpp
check/time_lw_E.cpp
check/time_lw_F.cpp
check/time_lw_G.cpp
check/time_lw_H.cpp
check/time_lw_IJKL.cpp
check/time_lw_M1.cpp
check/time_lw_M2.cpp
check/time_lw_N.cpp
check/time_lw_O.cpp
check/time_lw_P.cpp
check/time_lw_Pprime.cpp
check/time_lw_Q.cpp
check/time_lw_Qprime.cpp
check/time_parser.cpp
check/time_toeplitz.cpp
check/time_uvar_gcd.cpp
check/time_vandermonde.cpp
check/timer.cpp
check/timer.h
cmake/ginac-config.cmake.in [new file with mode: 0644]
cmake/modules/FindCLN.cmake
config/.gitignore [new file with mode: 0644]
config/config.rpath
configure.ac
doc/CMakeLists.txt
doc/examples/.gitignore [new file with mode: 0644]
doc/examples/CMakeLists.txt
doc/examples/Makefile.am
doc/examples/archive1.cpp
doc/examples/compile1.cpp
doc/examples/compile2.cpp
doc/examples/compile3.cpp
doc/examples/derivative.cpp
doc/examples/lanczos.cpp
doc/examples/mystring.cpp
doc/reference/.gitignore [new file with mode: 0644]
doc/reference/Doxyfooter.in
doc/reference/Makefile.am
doc/tutorial/.gitignore [new file with mode: 0644]
doc/tutorial/ginac.texi
ginac.pc.cmake
ginac.pc.in
ginac/.gitignore [new file with mode: 0644]
ginac/CMakeLists.txt
ginac/Makefile.am
ginac/add.cpp
ginac/add.h
ginac/archive.cpp
ginac/archive.h
ginac/assertion.h
ginac/basic.cpp
ginac/basic.h
ginac/class_info.h
ginac/clifford.cpp
ginac/clifford.h
ginac/color.cpp
ginac/color.h
ginac/compiler.h
ginac/constant.cpp
ginac/constant.h
ginac/container.h
ginac/ex.cpp
ginac/ex.h
ginac/excompiler.cpp
ginac/excompiler.h
ginac/expair.cpp
ginac/expair.h
ginac/expairseq.cpp
ginac/expairseq.h
ginac/exprseq.cpp
ginac/exprseq.h
ginac/factor.cpp
ginac/factor.h
ginac/fail.cpp
ginac/fail.h
ginac/fderivative.cpp
ginac/fderivative.h
ginac/flags.h
ginac/function.cppy
ginac/function.hppy
ginac/function.py [changed mode: 0755->0644]
ginac/ginac.h
ginac/hash_map.h
ginac/idx.cpp
ginac/idx.h
ginac/indexed.cpp
ginac/indexed.h
ginac/inifcns.cpp
ginac/inifcns.h
ginac/inifcns_elliptic.cpp [new file with mode: 0644]
ginac/inifcns_gamma.cpp
ginac/inifcns_nstdsums.cpp
ginac/inifcns_trans.cpp
ginac/integral.cpp
ginac/integral.h
ginac/integration_kernel.cpp [new file with mode: 0644]
ginac/integration_kernel.h [new file with mode: 0644]
ginac/lst.cpp
ginac/lst.h
ginac/matrix.cpp
ginac/matrix.h
ginac/mul.cpp
ginac/mul.h
ginac/ncmul.cpp
ginac/ncmul.h
ginac/normal.cpp
ginac/normal.h
ginac/numeric.cpp
ginac/numeric.h
ginac/operators.cpp
ginac/operators.h
ginac/parser/debug.h
ginac/parser/default_reader.cpp
ginac/parser/lexer.cpp
ginac/parser/lexer.h
ginac/parser/parse_binop_rhs.cpp
ginac/parser/parse_context.cpp
ginac/parser/parse_context.h
ginac/parser/parser.cpp
ginac/parser/parser.h
ginac/parser/parser_compat.cpp
ginac/polynomial/chinrem_gcd.cpp
ginac/polynomial/chinrem_gcd.h
ginac/polynomial/collect_vargs.cpp
ginac/polynomial/collect_vargs.h
ginac/polynomial/cra_garner.cpp
ginac/polynomial/cra_garner.h
ginac/polynomial/debug.h
ginac/polynomial/divide_in_z_p.cpp
ginac/polynomial/divide_in_z_p.h
ginac/polynomial/euclid_gcd_wrap.h
ginac/polynomial/eval_point_finder.h
ginac/polynomial/eval_uvar.h
ginac/polynomial/gcd_euclid.h
ginac/polynomial/gcd_uvar.cpp
ginac/polynomial/heur_gcd_uvar.h
ginac/polynomial/interpolate_padic_uvar.h
ginac/polynomial/mgcd.cpp
ginac/polynomial/mod_gcd.cpp
ginac/polynomial/mod_gcd.h
ginac/polynomial/newton_interpolate.h
ginac/polynomial/normalize.cpp
ginac/polynomial/normalize.h
ginac/polynomial/optimal_vars_finder.cpp
ginac/polynomial/optimal_vars_finder.h
ginac/polynomial/pgcd.cpp
ginac/polynomial/pgcd.h
ginac/polynomial/poly_cra.h
ginac/polynomial/prem_uvar.h
ginac/polynomial/primes_factory.h
ginac/polynomial/primpart_content.cpp
ginac/polynomial/remainder.cpp
ginac/polynomial/remainder.h
ginac/polynomial/ring_traits.h
ginac/polynomial/smod_helpers.h
ginac/polynomial/sr_gcd_uvar.h
ginac/polynomial/upoly.h
ginac/polynomial/upoly_io.cpp
ginac/polynomial/upoly_io.h
ginac/power.cpp
ginac/power.h
ginac/print.cpp
ginac/print.h
ginac/pseries.cpp
ginac/pseries.h
ginac/ptr.h
ginac/registrar.cpp
ginac/registrar.h
ginac/relational.cpp
ginac/relational.h
ginac/remember.cpp
ginac/remember.h
ginac/structure.h
ginac/symbol.cpp
ginac/symbol.h
ginac/symmetry.cpp
ginac/symmetry.h
ginac/tensor.cpp
ginac/tensor.h
ginac/utils.cpp
ginac/utils.h
ginac/utils_multi_iterator.h [new file with mode: 0644]
ginac/version.h
ginac/wildcard.cpp
ginac/wildcard.h
ginsh/.gitignore [new file with mode: 0644]
ginsh/CMakeLists.txt
ginsh/ginsh.1.in
ginsh/ginsh.h
ginsh/ginsh_extensions.h
ginsh/ginsh_fcn_help.py [changed mode: 0755->0644]
ginsh/ginsh_lexer.lpp
ginsh/ginsh_op_help.py [changed mode: 0755->0644]
ginsh/ginsh_parser.ypp
m4/.gitignore [new file with mode: 0644]
m4/ax_cxx_compile_stdcxx.m4
m4/host-cpu-c-abi.m4 [new file with mode: 0644]
m4/lib-ld.m4
m4/lib-link.m4
m4/lib-prefix.m4
scripts/fixupind.py [deleted file]
scripts/yaptu.py
tools/.gitignore [new file with mode: 0644]
tools/CMakeLists.txt
tools/viewgar.1.in
tools/viewgar.cpp

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..45ae18b
--- /dev/null
@@ -0,0 +1,27 @@
+.deps/
+.dirstamp
+core
+*.o
+*.lo
+*.la
+*.pyc
+*~
+*.orig
+*.rej
+core
+Makefile.in
+Makefile
+libtool
+aclocal.m4
+autom4te.cache/
+configure
+config.h
+config.log
+config.status
+ginac.pc
+GiNaC.spec
+CMakeFiles/
+cmake_install.cmake
+CMakeCache.txt
+CMakeDoxyfile.in
+CMakeDoxygenDefaults.cmake
diff --git a/AUTHORS b/AUTHORS
index 0e7f30920eaf05ed94e50d337d4ae73b71315081..f853d305add86bca372c40d6d3bfc983a4fc6d7e 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,32 +1,40 @@
-GiNaC was originally written by:
+Contacting the developers
+-------------------------
+
+If you have found a bug, have a patch or a question, or would like to
+make a suggestion please send email to one of our public mailing lists
+instead of to the authors.  This avoids both potential duplication of
+work and delays caused by possible vacations.  Mailing list subscription
+is explained at <https://www.ginac.de/Lists.html>.
 
- Christian Bauer <Christian.Bauer@uni-mainz.de>
- Alexander Frink <Alexander.Frink@uni-mainz.de>
- Richard Kreckel <Richard.Kreckel@uni-mainz.de>
 
-The following people have contributed code to GiNaC:
+Contributors
+------------
+
+The following people have contributed to GiNaC:
 
  Roberto Bagnara <bagnara@cs.unipr.it>
+ Christian Bauer <Christian.Bauer@uni-mainz.de>
  Chris Dams <Chris.Dams@mi.infn.it>
+ Matthias Dellweg <dellweg@tp1.uni-duesseldorf.de>
  Do Hoang Son <dhson@phys.hcmuns.edu.vn>
+ Oleg Finkelshteyn <olegfink@gmail.com>
+ Alexander Frink <Alexander.Frink@uni-mainz.de>
  Vladimir V. Kisil <kisilv@maths.leeds.ac.uk>
+ Richard B. Kreckel <kreckel@in.terlu.de>
  Vitaly Magerya <vmagerya@gmail.com>
  Markus Nullmeier <markus.nullmeier@urz.uni-heidelberg.de>
+ Bernard Parisse <Bernard.Parisse@ujf-grenoble.fr>
  Pearu Peterson <pearu@cens.ioc.ee>
  Benedikt Plümper <pluemper@thep.physik.uni-mainz.de>
+ Jan Rheinländer <jrheinlaender@gmx.de>
  Ben Sapp <bsapp@lanl.gov>
- Alexei Sheplyakov <varg@theor.jinr.ru>
+ Alexey Sheplyakov <varg@theor.jinr.ru>
+ Ralf Stephan <gtrwst9@gmail.com>
  Jens Vollinga <vollinga@thep.physik.uni-mainz.de>
+ Moritz Walden <mwalde01@students.uni-mainz.de>
  Stefan Weinzierl <weinzierl@uni-mainz.de>
+ Oliver Welzel <welzel@thep.physik.uni-mainz.de>
+ Ladislav Zejda <lzejda@gmail.com>
 
-(Please send email if you think you were forgotten.)
-
-
-Contacing the developers
-------------------------
-
-If you have found a bug, have a patch or a question, or would like to
-make a suggestion please send email to one of our public mailing lists
-instead of to the authors.  This avoids both potential duplication of
-work and delays caused by possible vacations.  Mailing list subscription
-is explained at <http://www.ginac.de/Lists.html>.
+(Please report to mailing-list if you think you've been forgotten.)
\ No newline at end of file
index cdb18f092cdecc1222de3daaf94e1deeb5be5d3c..aab81f253e796ab943a17315321f5c4c3d5fb00a 100644 (file)
@@ -1,15 +1,15 @@
 cmake_minimum_required(VERSION 3.1)
-set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
 
 project(GiNaC)
-file(STRINGS ${CMAKE_SOURCE_DIR}/ginac/version.h _ginac_vinfo REGEX "^#define[\t ]+GINACLIB_.*_VERSION.*")
+file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/ginac/version.h _ginac_vinfo REGEX "^#define[\t ]+GINACLIB_.*_VERSION.*")
 string(REGEX REPLACE "^.*GINACLIB_MAJOR_VERSION[ \t]+([0-9]+).*" "\\1" GINAC_MAJOR_VERSION "${_ginac_vinfo}")
 string(REGEX REPLACE "^.*GINACLIB_MINOR_VERSION[ \t]+([0-9]+).*" "\\1" GINAC_MINOR_VERSION "${_ginac_vinfo}")
 string(REGEX REPLACE "^.*GINACLIB_MICRO_VERSION[ \t]+([0-9]+).*" "\\1" GINAC_MICRO_VERSION "${_ginac_vinfo}")
 set(GINAC_VERSION "${GINAC_MAJOR_VERSION}.${GINAC_MINOR_VERSION}.${GINAC_MICRO_VERSION}")
 
 # Library versioning info
-file(STRINGS ${CMAKE_SOURCE_DIR}/ginac/version.h _ginac_vinfo REGEX "^#define[\t ]+GINAC_LT_.*")
+file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/ginac/version.h _ginac_vinfo REGEX "^#define[\t ]+GINAC_LT_.*")
 string(REGEX REPLACE "^.*GINAC_LT_CURRENT[ \t]+([0-9]+).*" "\\1" ginac_lt_current "${_ginac_vinfo}")
 string(REGEX REPLACE "^.*GINAC_LT_AGE[ \t]+([0-9]+).*" "\\1" ginac_lt_age "${_ginac_vinfo}")
 string(REGEX REPLACE "^.*GINAC_LT_REVISION[ \t]+([0-9]+).*" "\\1" ginac_lt_revision "${_ginac_vinfo}")
@@ -17,65 +17,46 @@ string(REGEX REPLACE "^.*GINAC_LT_REVISION[ \t]+([0-9]+).*" "\\1" ginac_lt_revis
 math(EXPR ginaclib_soversion "${ginac_lt_current} - ${ginac_lt_age}")
 set(ginaclib_version ${ginaclib_soversion}.${ginac_lt_age}.${ginac_lt_revision})
 
+include(GNUInstallDirs)
+
 # make check
 enable_testing()
-add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
+if (NOT TARGET check)
+       add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
+endif()
+if (NOT TARGET test_suite)
+       add_custom_target(test_suite)
+endif()
+if (WIN32)
+       if (NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+               set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
+       endif()
+endif()
 # make info
-add_custom_target(info ALL)
-add_custom_target(html)
-add_custom_target(pdf)
+if (NOT TARGET info)
+       add_custom_target(info ALL)
+endif()
+if (NOT TARGET html)
+       add_custom_target(html)
+endif()
+if (NOT TARGET pdf)
+       add_custom_target(pdf)
+endif()
 
 set (CMAKE_CXX_STANDARD 11)
 
-find_package(CLN 1.2.2 REQUIRED)
-include_directories(${CLN_INCLUDE_DIR})
+if (NOT DEFINED CLN_SOURCE_DIR)
+       set(CLN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cln)
+endif()
+if (EXISTS ${CLN_SOURCE_DIR}/CMakeLists.txt)
+       add_subdirectory(${CLN_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/cln)
+else()
+       find_package(CLN 1.2.2 REQUIRED)
+endif()
 
 include(CheckIncludeFile)
 check_include_file("unistd.h" HAVE_UNISTD_H)
 
-include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/ginac)
-
-# This macro implements some very special logic how to deal with the cache.
-# By default the various install locations inherit their value from their
-#"parent" variable, so if you set CMAKE_INSTALL_PREFIX, then
-# EXEC_INSTALL_PREFIX, BIN_INSTALL_DIR, LIB_INSTALL_DIR, etc will calculate
-# their value by appending subdirs to CMAKE_INSTALL_PREFIX.
-# This would work just fine without using the cache.
-# But if somebody wants e.g. a different EXEC_INSTALL_PREFIX this value
-# has to go into the cache, otherwise it will be forgotten on the next cmake
-# run. Once a variable is in the cache, it doesn't depend on its "parent"
-# variables anymore and you can only change it by editing it directly.
-# This macro helps in this regard, because as long as you don't set one
-# of the variables explicitly to some location, the value will be computed
-# from parents of the variable in question. So modifying CMAKE_INSTALL_PREFIX
-# later on will have the desired effect.
-# But once you decide to set e.g. EXEC_INSTALL_PREFIX to some special
-# location this will go into the cache and it will no longer depend on
-# CMAKE_INSTALL_PREFIX.
-
-macro(_set_fancy _var _value _comment)
-       set(predefinedvalue "${_value}")
-       if ("${CMAKE_INSTALL_PREFIX}" STREQUAL "${GINAC_INSTALL_DIR}" AND DEFINED GINAC_${_var})
-               set(predefinedvalue "${GINAC_${_var}}")
-       endif()
-       if (NOT DEFINED ${_var})
-               set(${_var} ${predefinedvalue})
-       else()
-               set(${_var} "${${_var}}" CACHE PATH "${_comment}")
-       endif()
-endmacro(_set_fancy)
-
-_set_fancy(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
-          "Base directory for libraries and executables")
-_set_fancy(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib"
-          "Libraries installation directory")
-_set_fancy(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin"
-          "Binaries installation directory")
-_set_fancy(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/share"
-          "Base directory for architecture independent files")
-_set_fancy(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include"
-          "Headers installation directory")
-
 if (NOT DEFINED BUILD_SHARED_LIBS)
        if (NOT MSVC)
                set(BUILD_SHARED_LIBS true)
@@ -99,7 +80,7 @@ set(_wl_rpath "${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG}")
 
 # rpath for the pkg-config meta-data.
 set(_ginaclib_rpath "${_wl_rpath}${_ginac_rpath_reloc}")
-list(FIND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "${LIB_INSTALL_DIR}" isSystemDir)
+list(FIND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_FULL_LIBDIR}" isSystemDir)
 if ("${isSystemDir}" STREQUAL "-1")
        list(APPEND _ginaclib_rpath "${_wl_rpath}\${libdir}")
 endif()
@@ -110,12 +91,12 @@ if (NOT CMAKE_SKIP_RPATH)
        endif()
 endif()
 
-configure_file(${CMAKE_SOURCE_DIR}/ginac.pc.cmake ${CMAKE_BINARY_DIR}/ginac.pc @ONLY)
-install(FILES ${CMAKE_BINARY_DIR}/ginac.pc DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ginac.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/ginac.pc @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ginac.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
 
 # rpath for libginac.so itself, ginsh, and friends
 set(_ginac_rpath ${_ginac_rpath_reloc})
-foreach(_d ${CLN_LIBRARY_DIRS} ${LIB_INSTALL_DIR})
+foreach(_d ${CLN_LIBRARY_DIRS} ${CMAKE_INSTALL_FULL_LIBDIR})
        list(FIND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "${_d}" isSystemDir)
        if ("${isSystemDir}" STREQUAL "-1")
                list(APPEND _ginac_rpath "${_d}")
@@ -131,16 +112,16 @@ if (NOT DEFINED CMAKE_INSTALL_RPATH)
        set(CMAKE_INSTALL_RPATH ${ginac_rpath})
 endif()
 if (APPLE AND NOT DEFINED CMAKE_INSTALL_NAME_DIR)
-       set(CMAKE_INSTALL_NAME_DIR ${LIB_INSTALL_DIR})
+       set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR})
 endif()
 
-list(FIND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "${LIB_INSTALL_DIR}" isSystemDir)
+list(FIND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_FULL_LIBDIR}" isSystemDir)
 if ("${isSystemDir}" STREQUAL "-1")
        string(REPLACE ":" ";" _install_rpath "${CMAKE_INSTALL_RPATH}")
-       list(FIND _install_rpath "${LIB_INSTALL_DIR}" _is_rpath_consistent)
+       list(FIND _install_rpath "${CMAKE_INSTALL_FULL_LIBDIR}" _is_rpath_consistent)
        if ("${_is_rpath_consistent}" STREQUAL "-1")
                message(WARNING "the libginac.so library will be installed into "
-                               "a non-standard directory (${LIB_INSTALL_DIR}), "
+                       "a non-standard directory (${CMAKE_INSTALL_FULL_LIBDIR}), "
                                "however, the rpath (${_install_rpath}) "
                                "does not contain that directory. Most likely "
                                "things won't work without extra configuration "
@@ -148,6 +129,23 @@ if ("${isSystemDir}" STREQUAL "-1")
        endif()
 endif()
 
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file(
+       ${CMAKE_CURRENT_BINARY_DIR}/ginac-config-version.cmake
+       VERSION ${GINAC_VERSION}
+       COMPATIBILITY AnyNewerVersion
+)
+
+configure_package_config_file(${CMAKE_CURRENT_LIST_DIR}/cmake/ginac-config.cmake.in
+       ${CMAKE_CURRENT_BINARY_DIR}/ginac-config.cmake
+       INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ginac
+)
+
+install(FILES
+       ${CMAKE_CURRENT_BINARY_DIR}/ginac-config.cmake
+       ${CMAKE_CURRENT_BINARY_DIR}/ginac-config-version.cmake
+       DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ginac
+)
 
 include(FindFLEX)
 include(FindBISON)
@@ -167,9 +165,16 @@ endif()
 
 find_program(MAKEINFO makeinfo)
 find_program(FIG2DEV fig2dev)
+find_program(PYTHON python)
+if (NOT PYTHON)
+       find_program(PYTHON python3)
+endif()
+if (NOT PYTHON)
+       message(FATAL_ERROR "Python version 3 or 2 is required")
+endif()
+
 
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
-add_definitions(-DHAVE_CONFIG_H)
 
 if (NOT LIBEXECDIR)
        set (LIBEXECDIR "${CMAKE_INSTALL_PREFIX}/libexec")
diff --git a/CVSROOT/checkoutlist b/CVSROOT/checkoutlist
deleted file mode 100644 (file)
index b04b350..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# The "checkoutlist" file is used to support additional version controlled
-# administrative files in $CVSROOT/CVSROOT, such as template files.
-#
-# The first entry on a line is a filename which will be checked out from
-# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
-# The remainder of the line is an error message to use if the file cannot
-# be checked out.
-#
-# File format:
-#
-#      [<whitespace>]<filename><whitespace><error message><end-of-line>
-#
-# comment lines begin with '#'
diff --git a/CVSROOT/commitinfo b/CVSROOT/commitinfo
deleted file mode 100644 (file)
index b19e7b7..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# The "commitinfo" file is used to control pre-commit checks.
-# The filter on the right is invoked with the repository and a list 
-# of files to check.  A non-zero exit of the filter program will 
-# cause the commit to be aborted.
-#
-# The first entry on a line is a regular expression which is tested
-# against the directory that the change is being committed to, relative
-# to the $CVSROOT.  For the first match that is found, then the remainder
-# of the line is the name of the filter to run.
-#
-# If the repository name does not match any of the regular expressions in this
-# file, the "DEFAULT" line is used, if it is specified.
-#
-# If the name "ALL" appears as a regular expression it is always used
-# in addition to the first matching regex or "DEFAULT".
diff --git a/CVSROOT/config b/CVSROOT/config
deleted file mode 100644 (file)
index 51b03f6..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# Set this to "no" if pserver shouldn't check system users/passwords
-#SystemAuth=no
-
-# Set `PreservePermissions' to `yes' to save file status information
-# in the repository.
-#PreservePermissions=no
diff --git a/CVSROOT/cvswrappers b/CVSROOT/cvswrappers
deleted file mode 100644 (file)
index 0accaf1..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file affects handling of files based on their names.
-#
-# The -t/-f options allow one to treat directories of files
-# as a single file, or to transform a file in other ways on
-# its way in and out of CVS.
-#
-# The -m option specifies whether CVS attempts to merge files.
-#
-# The -k option specifies keyword expansion (e.g. -kb for binary).
-#
-# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
-#
-#  wildcard    [option value][option value]...
-#
-#  where option is one of
-#  -f          from cvs filter         value: path to filter
-#  -t          to cvs filter           value: path to filter
-#  -m          update methodology      value: MERGE or COPY
-#  -k          expansion mode          value: b, o, kkv, &c
-#
-#  and value is a single-quote delimited value.
-# For example:
-#*.gif -k 'b'
diff --git a/CVSROOT/editinfo b/CVSROOT/editinfo
deleted file mode 100644 (file)
index d78886c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# The "editinfo" file is used to allow verification of logging
-# information.  It works best when a template (as specified in the
-# rcsinfo file) is provided for the logging procedure.  Given a
-# template with locations for, a bug-id number, a list of people who
-# reviewed the code before it can be checked in, and an external
-# process to catalog the differences that were code reviewed, the
-# following test can be applied to the code:
-#
-#   Making sure that the entered bug-id number is correct.
-#   Validating that the code that was reviewed is indeed the code being
-#       checked in (using the bug-id number or a seperate review
-#       number to identify this particular code set.).
-#
-# If any of the above test failed, then the commit would be aborted.
-#
-# Actions such as mailing a copy of the report to each reviewer are
-# better handled by an entry in the loginfo file.
-#
-# One thing that should be noted is the the ALL keyword is not
-# supported.  There can be only one entry that matches a given
-# repository.
diff --git a/CVSROOT/loginfo b/CVSROOT/loginfo
deleted file mode 100644 (file)
index 5a59f0a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# The "loginfo" file controls where "cvs commit" log information
-# is sent.  The first entry on a line is a regular expression which must match
-# the directory that the change is being made to, relative to the
-# $CVSROOT.  If a match is found, then the remainder of the line is a filter
-# program that should expect log information on its standard input.
-#
-# If the repository name does not match any of the regular expressions in this
-# file, the "DEFAULT" line is used, if it is specified.
-#
-# If the name ALL appears as a regular expression it is always used
-# in addition to the first matching regex or DEFAULT.
-#
-# You may specify a format string as part of the
-# filter.  The string is composed of a `%' followed
-# by a single format character, or followed by a set of format
-# characters surrounded by `{' and `}' as separators.  The format
-# characters are:
-#
-#   s = file name
-#   V = old version number (pre-checkin)
-#   v = new version number (post-checkin)
-#
-# For example:
-#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
-# or
-#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
diff --git a/CVSROOT/modules b/CVSROOT/modules
deleted file mode 100644 (file)
index cb9e9ef..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# Three different line formats are valid:
-#      key     -a    aliases...
-#      key [options] directory
-#      key [options] directory files...
-#
-# Where "options" are composed of:
-#      -i prog         Run "prog" on "cvs commit" from top-level of module.
-#      -o prog         Run "prog" on "cvs checkout" of module.
-#      -e prog         Run "prog" on "cvs export" of module.
-#      -t prog         Run "prog" on "cvs rtag" of module.
-#      -u prog         Run "prog" on "cvs update" of module.
-#      -d dir          Place module in directory "dir" instead of module name.
-#      -l              Top-level directory only -- do not recurse.
-#
-# NOTE:  If you change any of the "Run" options above, you'll have to
-# release and re-checkout any working directories of these modules.
-#
-# And "directory" is a path to a directory relative to $CVSROOT.
-#
-# The "-a" option specifies an alias.  An alias is interpreted as if
-# everything on the right of the "-a" had been typed on the command line.
-#
-# You can encode a module within a module by using the special '&'
-# character to interpose another module into the current module.  This
-# can be useful for creating a module that consists of many directories
-# spread out over the entire source repository.
diff --git a/CVSROOT/notify b/CVSROOT/notify
deleted file mode 100644 (file)
index 34f0bc2..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# The "notify" file controls where notifications from watches set by
-# "cvs watch add" or "cvs edit" are sent.  The first entry on a line is
-# a regular expression which is tested against the directory that the
-# change is being made to, relative to the $CVSROOT.  If it matches,
-# then the remainder of the line is a filter program that should contain
-# one occurrence of %s for the user to notify, and information on its
-# standard input.
-#
-# "ALL" or "DEFAULT" can be used in place of the regular expression.
-#
-# For example:
-#ALL mail %s -s "CVS notification"
diff --git a/CVSROOT/rcsinfo b/CVSROOT/rcsinfo
deleted file mode 100644 (file)
index 49e59f4..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# The "rcsinfo" file is used to control templates with which the editor
-# is invoked on commit and import.
-#
-# The first entry on a line is a regular expression which is tested
-# against the directory that the change is being made to, relative to the
-# $CVSROOT.  For the first match that is found, then the remainder of the
-# line is the name of the file that contains the template.
-#
-# If the repository name does not match any of the regular expressions in this
-# file, the "DEFAULT" line is used, if it is specified.
-#
-# If the name "ALL" appears as a regular expression it is always used
-# in addition to the first matching regex or "DEFAULT".
diff --git a/CVSROOT/taginfo b/CVSROOT/taginfo
deleted file mode 100644 (file)
index 274a46d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# The "taginfo" file is used to control pre-tag checks.
-# The filter on the right is invoked with the following arguments:
-#
-# $1 -- tagname
-# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
-# $3 -- repository
-# $4->  file revision [file revision ...]
-#
-# A non-zero exit of the filter program will cause the tag to be aborted.
-#
-# The first entry on a line is a regular expression which is tested
-# against the directory that the change is being committed to, relative
-# to the $CVSROOT.  For the first match that is found, then the remainder
-# of the line is the name of the filter to run.
-#
-# If the repository name does not match any of the regular expressions in this
-# file, the "DEFAULT" line is used, if it is specified.
-#
-# If the name "ALL" appears as a regular expression it is always used
-# in addition to the first matching regex or "DEFAULT".
diff --git a/CVSROOT/verifymsg b/CVSROOT/verifymsg
deleted file mode 100644 (file)
index 86f747c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# The "verifymsg" file is used to allow verification of logging
-# information.  It works best when a template (as specified in the
-# rcsinfo file) is provided for the logging procedure.  Given a
-# template with locations for, a bug-id number, a list of people who
-# reviewed the code before it can be checked in, and an external
-# process to catalog the differences that were code reviewed, the
-# following test can be applied to the code:
-#
-#   Making sure that the entered bug-id number is correct.
-#   Validating that the code that was reviewed is indeed the code being
-#       checked in (using the bug-id number or a seperate review
-#       number to identify this particular code set.).
-#
-# If any of the above test failed, then the commit would be aborted.
-#
-# Actions such as mailing a copy of the report to each reviewer are
-# better handled by an entry in the loginfo file.
-#
-# One thing that should be noted is the the ALL keyword is not
-# supported.  There can be only one entry that matches a given
-# repository.
index b57ef5bac11d572659fb653c9b4586f5a616b25c..7008bb4901afc9a7126f355d8ccbf8f22dc70513 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,4 +4,4 @@ logged.  This is how to get anonymous read-only access:
 $ git clone git://www.ginac.de/ginac.git ginac
 $ cd ginac; git whatchanged
 Alternatively you can browse the repository on-line at
-http://www.ginac.de/ginac.git
+https://www.ginac.de/ginac.git
index 4c8ebca1c3ffc314a979e9e59e827a3432b5b13a..1ddf85f34f6ea589eeed25e51bc78d5c35e61b69 100644 (file)
@@ -8,8 +8,8 @@ Version: %{version}
 Release: %{release}
 License: GPL
 Group: System Environment/Libraries
-Source0: http://www.ginac.de/%{name}-%{version}.tar.bz2
-URL: http://www.ginac.de/
+Source0: https://www.ginac.de/%{name}-%{version}.tar.bz2
+URL: https://www.ginac.de/
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 Prefix: %{_prefix}
 
diff --git a/INSTALL b/INSTALL
index d506b79a311f22b6a70e851e5fa3b2974fd30a31..07e7cf42613395608ab1a3cec6c8962b9fc849bc 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -2,7 +2,7 @@ PREREQUISITES
 =============
 
 GiNaC requires the CLN library by Bruno Haible installed on your system.
-It is available from <http://www.ginac.de/CLN/>.
+It is available from <https://www.ginac.de/CLN/>.
 
 You will also need a decent ISO C++-11 compiler. We recommend the C++
 compiler from the GNU compiler collection, GCC >= 4.8. If you have a
@@ -14,20 +14,20 @@ The pkg-config utility is required for configuration, it can be downloaded
 from <http://pkg-config.freedesktop.org/>. Also, Python 3 is required.
 
 To build the GiNaC tutorial and reference manual the doxygen utility
-(it can be downloaded from http://www.stack.nl/~dimitri/doxygen) and
-TeX are necessary.
+(it can be downloaded from https://www.doxygen.nl/) and TeX are necessary.
 
 Known to work with:
  - Linux on x86 and x86_64 using
-   - GCC 4.8, 4.9, 5.1, 5.2, 5.3, and 6.1
-   - Clang 3.5, 3.6, 3.7, 3.8
+   - GCC 4.8, 4.9, 5.x, 6.x, 7.x, 8.x, and 9.x
+   - Clang 3.5, 3.6, 3.7, 3.8, 6.x, 7.x, 8.x, and 9.x
 
 Known not to work with:
  - Clang 2.7 and earlier due to poor C++ support.
  - GCC < 4.6.0 due to missing C++-11 support
 
 If you install from git, you also need GNU autoconf (>=2.59), automake (>=1.8),
-libtool (>= 1.5), python3, bison (>= 2.3), flex (>= 2.5.33) to be installed.
+libtool (>= 1.5), python (version 2.7 or 3.x), bison (>= 2.3), flex (>= 2.5.33)
+to be installed.
 
 
 INSTALLATION
@@ -87,7 +87,7 @@ First, download the code:
 Secondly, make sure all required software is installed. This is *really*
 important step. If some package is missing, the `configure' script might
 be misgenerated, see e.g. this discussion:
-<http://www.ginac.de/pipermail/ginac-list/2007-November/001263.html>
+<https://www.ginac.de/pipermail/ginac-list/2007-November/001263.html>
 
 Finally, run
 
index 292f0fb81c36bbb7cb49d2492ac4fa3cdf6facec..c36c18fc9c85dc22d91fe2b87cedbb688ae60bde 100644 (file)
@@ -2,17 +2,17 @@ PREREQUISITES
 =============
 
 1. A decent ISO C++-11 compiler. GCC (version >= 4.9) is recommended.
-2. CLN library (http://www.ginac.de/CLN), version >= 1.2.2
+2. CLN library (https://www.ginac.de/CLN), version >= 1.2.2
 3. CMake, version >= 2.8 (version 2.6.x might work too).
-4. Python, version >= 2.6
+4. Python 3
 5. (optional) pkg-config utility (http://pkg-config.freedesktop.org)
 6. (optional) bison (>= 2.3), flex (2.5.33), GNU readline (>= 4.3). These
    are necessary to build ginsh, the GiNaC interactive shell, and can be
    skipped if you don't intend to use ginsh (i.e. you need the GiNaC library
    for compiling another piece of a software).
 7. (optional) To build the GiNaC tutorial and reference manual the doxygen
-   utility (it can be downloaded from http://www.stack.nl/~dimitri/doxygen)
-   and TeX are necessary.
+   utility (it can be downloaded from https://www.doxygen.nl/) and TeX are
+   necessary.
 
 INSTALLATION
 ============
index b651383cf687c7f29ab03475d1b4ff0853352453..8d66956d90930de471229c3f34bc53dc4a0eb5a1 100644 (file)
@@ -11,12 +11,13 @@ CMAKE_FILES = CMakeLists.txt \
              ginac.pc.cmake \
              config.cmake.in \
              INSTALL.CMake \
+             cmake/ginac-config.cmake.in \
              cmake/modules/FindCLN.cmake \
              cmake/modules/FindReadline.cmake \
              cmake/modules/FindGiNaC.cmake \
              cmake/modules/FindLibDL.cmake
 
-BUILD_HELPERS = scripts/yaptu.py scripts/fixupind.py
+BUILD_HELPERS = scripts/yaptu.py
 
 # All the rest of the distributed files
 EXTRA_DIST = ginac.pc GiNaC.spec $(BUILD_HELPERS) $(CMAKE_FILES)
diff --git a/NEWS b/NEWS
index feed081efc31adfa454e7b2509595429a030b16d..828b0130e9dbc02cae70f73d060937df6252d4fd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,70 @@
 This file records noteworthy changes.
 
+1.8.7 (12 August 2023)
+* Fix series expansion of polynomial(x)^n for small and large n.
+* Fix bugs in internal parser from strings.
+* Make ginsh evaluate line-by-line in non-interactive mode.
+* Several build fixes.
+
+1.8.6 (8 February 2023)
+* Fix wrong numeric info on transcendental functions.
+* Fix crash of evaluation of binomial(n, k) with negative integer n, k.
+
+1.8.5 (1 January 2023)
+* Speed up multivariate polynomial factorization; fix it in some rare
+  corner cases where it didn't previously terminate.
+
+1.8.4 (19 September 2022)
+* Add support for sqrfree_parfrac().
+* Add info methods for transcendental functions.
+
+1.8.3 (23 March 2022)
+* series_to_poly() can be used from ginsh.
+* Fix power::to_polynomial() for posint exponents.
+* Fix power::subs() in some special cases.
+
+1.8.2 (1 January 2022)
+* Fix elusive bug in comparing relational objects.
+* Ensure modular_form_kernel::series() includes an Order term.
+
+1.8.1 (9 August 2021)
+* Add method relational::canonical() and improve conversion of relational to
+  Boolean (it now works on many simple symbolic cases).
+* Improve normalization of negative exponents.
+* Fix indexing multiply referenced objects with ex::operator[].
+* Make functions evalf() their arguments before doing own evalf().
+* Fix bugs in H_evalf() and in evaluation of iterated integrals.
+* Several portability improvements and compiler warning fixes.
+
+1.8.0 (14 October 2020)
+* New routines for the numerical evaluation of iterated integrals like
+  elliptic multiple polylogarithms or iterated integrals of modular forms.
+* Stronger normalization methods for expressions with powers. Where this
+  is safe, GiNaC now tries replacing various kinds of powers in order to
+  find and cancel common subexpressions.
+* Improved CMake build.
+
+1.7.11 (3 August 2020)
+* Fix elusive bugs in factor() and in expand().
+
+1.7.10 (28 June 2020)
+* Fix collect_common_factors() for hidden zero arguments.
+* Fix build on modern systems (C++20 and Python3).
+
+1.7.9 (11 April 2020)
+* Fix unarchiving of overloaded functions.
+* Fix MinGW64 build.
+
+1.7.8 (7 October 2019)
+* Fix pseries::evalf(), broken since 1.7.0.
+* Fix a corner-case bug in H_evalf().
+
+1.7.7 (22 September 2019)
+* Fix unarchiving empty containers.
+* Remove obsolete exhashmap implementation.
+* Fix issues with zeta computation.
+* Build with Python3.
+
 1.7.6 (22 April 2019)
 * Fix a bug in mul::series() about asymptotic order term.
 * Fix cl_N code generation for small negative integers.
diff --git a/README b/README
index 90e549c362beadf3b9e726a9d69bbc965b6464f5..e828a0eba892efa7e21ad18fd1c09bf69d057802 100644 (file)
--- a/README
+++ b/README
@@ -8,7 +8,7 @@ with more established areas of computer science (like computation-intense
 numeric applications, graphical interfaces, etc.) under one roof.
 
 The official web site is:
-  http://www.ginac.de/
+  https://www.ginac.de/
 
 A mailing list is located at:
   ginac-list@ginac.de
@@ -17,7 +17,7 @@ You need to be subscribed to be able to post to the list. To subscribe,
 please follow the instructions on
   https://www.cebix.net/mailman/listinfo/ginac-list
 
-See http://www.ginac.de/Lists.html for the list policy.
+See https://www.ginac.de/Lists.html for the list policy.
 
 
 Installation
index 53b45e5a9e8c0ac36712bc13206561eb6a40151e..35cd3862fefe3f331e6a72b93e947b9385a63416 100644 (file)
@@ -22,48 +22,6 @@ define(GINAC_GET_VERSION,
 define(GINAC_GET_LTVERSION,
 [GINAC_HEADER_GETVAL(GINAC_LT_$1,[ginac/version.h])])
 
-dnl Usage: GINAC_STD_CXX_HEADERS
-dnl Check for standard C++ headers, bail out if something is missing.
-AC_DEFUN([GINAC_STD_CXX_HEADERS], [
-AC_CACHE_CHECK([for standard C++ header files], [ginac_cv_std_cxx_headers], [
-       ginac_cv_std_cxx_headers="no"
-       AC_LANG_PUSH([C++])
-       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-               #include <algorithm>
-               #include <cstddef>
-               #include <cstdio>
-               #include <cstdlib>
-               #include <cstring>
-               #include <cstdint>
-               #include <ctime>
-               #include <fstream>
-               #include <functional>
-               #include <iomanip>
-               #include <ios>
-               #include <iosfwd>
-               #include <iostream>
-               #include <iterator>
-               #include <limits>
-               #include <list>
-               #include <map>
-               #include <memory>
-               #include <numeric>
-               #include <ostream>
-               #include <set>
-               #include <sstream>
-               #include <stack>
-               #include <stdexcept>
-               #include <string>
-               #include <typeinfo>
-               #include <utility>
-               #include <vector>
-               ]])], [ginac_cv_std_cxx_headers="yes"])
-       AC_LANG_POP([C++])])
-if test "${ginac_cv_std_cxx_headers}" != "yes"; then
-       AC_MSG_ERROR([Standard ISO C++ headers are missing])
-fi
-])
-
 dnl Usage: GINAC_LIBREADLINE
 dnl
 dnl Check if GNU readline library and headers are avialable.
@@ -181,13 +139,13 @@ fi])
 AC_DEFUN([GINAC_HAVE_RUSAGE],
 [AC_CACHE_CHECK([whether struct rusage is declared in <sys/resource.h>],
 ac_cv_have_rusage,
- [AC_TRY_COMPILE([#include <sys/times.h>
-                  #include <sys/resource.h>],
-                  [struct rusage resUsage;
-                   getrusage(RUSAGE_SELF, &resUsage);
-                   return 0;],
-                 [ac_cv_have_rusage=yes],
-                 [ac_cv_have_rusage=no])
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/times.h>
+                                       #include <sys/resource.h>]],
+                                     [[struct rusage resUsage;
+                                       getrusage(RUSAGE_SELF, &resUsage);
+                                       return 0;]])],
+                    [ac_cv_have_rusage=yes],
+                    [ac_cv_have_rusage=no])
 ])
 CONFIG_RUSAGE="no"
 if test "$ac_cv_have_rusage" = yes; then
diff --git a/check/.gitignore b/check/.gitignore
new file mode 100644 (file)
index 0000000..6da20c8
--- /dev/null
@@ -0,0 +1,65 @@
+.libs/
+*.log
+*.trs
+exam.gar
+exam_archive
+exam_clifford
+exam_collect
+exam_color
+exam_differentiation
+exam_factor
+exam_function_exvector
+exam_heur_gcd
+exam_indexed
+exam_inifcns
+exam_inifcns_nstdsums
+exam_inifcns_elliptic
+exam_lsolve
+exam_matrices
+exam_misc
+exam_pgcd
+exam_mod_gcd
+exam_normalization
+exam_sqrfree
+exam_numeric
+exam_paranoia
+exam_polygcd
+exam_relational
+exam_collect_common_factors
+exam_powerlaws
+exam_pseries
+exam_chinrem_gcd
+exam_real_imag
+exam_structure
+exam_match
+exam_parser
+check_inifcns
+check_lsolve
+check_matrices
+check_numeric
+check_cra
+time_antipode
+time_dennyfliegner
+time_fateman_expand
+time_gammaseries
+time_lw_A
+time_lw_B
+time_lw_C
+time_lw_D
+time_lw_E
+time_lw_F
+time_lw_G
+time_lw_H
+time_lw_IJKL
+time_lw_M1
+time_lw_M2
+time_lw_N
+time_lw_O
+time_lw_P
+time_lw_Pprime
+time_lw_Q
+time_lw_Qprime
+time_parser
+time_toeplitz
+time_uvar_gcd
+time_vandermonde
index 58f9736b2a7536c32cfa04b6e1285c6bd6ad8234..db9491151e1ed3cdc441d4f095f497eb75ea7dc2 100644 (file)
@@ -1,25 +1,21 @@
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../ginac)
-add_definitions(-DIN_GINAC)
 
-set(ginac_tests
-       check_numeric
-       check_inifcns
-       check_matrices
-       check_lsolve
-       check_mul_info
-       heur_gcd_bug
+set(ginac_exams
        exam_paranoia
        exam_heur_gcd
-       match_bug
-       parser_bugs
-       exam_numeric_archive
+       exam_match
+       exam_parser
        exam_numeric
+       exam_relational
        exam_powerlaws
+       exam_collect
        exam_inifcns
        exam_inifcns_nstdsums
+       exam_inifcns_elliptic
        exam_differentiation
        exam_polygcd
+       exam_collect_common_factors
        exam_normalization
+       exam_sqrfree
        exam_factor
        exam_pseries
        exam_matrices
@@ -29,22 +25,26 @@ set(ginac_tests
        exam_clifford
        exam_archive
        exam_structure
-       exam_hashmap
        exam_misc
+       exam_pgcd
        exam_mod_gcd
-       exam_cra
        exam_real_imag
-       bugme_chinrem_gcd
-       factor_univariate_bug
-       pgcd_relatively_prime_bug
-       pgcd_infinite_loop)
+       exam_chinrem_gcd
+       exam_function_exvector
+)
+
+set(ginac_checks
+       check_numeric
+       check_inifcns
+       check_matrices
+       check_lsolve
+       check_cra)
 
 set(ginac_timings
        time_dennyfliegner
        time_gammaseries
        time_vandermonde
        time_toeplitz
-       time_hashmap
        time_lw_A
        time_lw_B
        time_lw_C
@@ -72,23 +72,27 @@ macro(add_ginac_test thename)
                set(${thename}_sources ${thename}.cpp ${${thename}_extra_src})
        endif()
        add_executable(${thename} EXCLUDE_FROM_ALL ${${thename}_sources})
-       target_link_libraries(${thename} ginac ${LIBDL_LIBRARIES})
+       target_link_libraries(${thename} ginac::ginac)
+       add_dependencies(test_suite ${thename})
        add_dependencies(check ${thename})
-       add_test(NAME ${thename} COMMAND ${thename}${CMAKE_EXECUTABLE_SUFFIX})
+       add_test(NAME ${thename} COMMAND $<TARGET_FILE:${thename}>)
 endmacro()
 
 macro(add_ginac_timing thename)
        set(${thename}_extra_src timer.cpp randomize_serials.cpp)
        add_ginac_test(${thename})
+       target_compile_definitions(${thename} PRIVATE HAVE_CONFIG_H)
 endmacro()
 
 set(check_matrices_extra_src genex.cpp)
 set(check_lsolve_extra_src genex.cpp)
-set(exam_heur_gcd_sources heur_gcd_bug.cpp)
-set(exam_numeric_archive_sources numeric_archive.cpp)
 
-foreach(tst ${ginac_tests})
-       add_ginac_test(${tst})
+foreach(exm ${ginac_exams})
+       add_ginac_test(${exm})
+endforeach()
+
+foreach(chk ${ginac_checks})
+       add_ginac_test(${chk})
 endforeach()
 
 foreach(tmr ${ginac_timings})
diff --git a/check/FILES b/check/FILES
new file mode 100644 (file)
index 0000000..4f87c57
--- /dev/null
@@ -0,0 +1,8 @@
+Files in this directory
+=======================
+
+exam*:  test result for specific input (like a pupil's exam)
+
+check*: test coherence of results among each other, with random input
+
+time*:  measure run-time
index 0f7e035e0d037dc8e10f7dc3256eafef01a615ee..0c119d52c2bfaf1ccea587921bb158a41b0c02ec 100644 (file)
@@ -1,47 +1,47 @@
 ## Process this file with automake to produce Makefile.in
 
-CHECKS = check_numeric \
-        check_inifcns \
-        check_matrices \
-        check_lsolve 
-
 EXAMS = exam_paranoia \
        exam_heur_gcd \
-       match_bug \
-       parser_bugs \
-       exam_numeric_archive \
+       exam_match \
+       exam_parser \
        exam_numeric \
-       exam_powerlaws  \
+       exam_relational \
+       exam_powerlaws \
+       exam_collect \
        exam_inifcns \
        exam_inifcns_nstdsums \
+       exam_inifcns_elliptic \
        exam_differentiation  \
-       exam_polygcd  \
-       exam_normalization  \
+       exam_polygcd \
+       exam_collect_common_factors \
+       exam_normalization \
+       exam_sqrfree  \
        exam_factor \
        exam_pseries  \
        exam_matrices  \
        exam_lsolve  \
        exam_indexed  \
-       exam_color  \
+       exam_color \
        exam_clifford  \
        exam_archive  \
        exam_structure  \
-       exam_hashmap  \
        exam_misc \
+       exam_pgcd \
        exam_mod_gcd \
-       check_mul_info \
-       bugme_chinrem_gcd \
-       factor_univariate_bug \
-       pgcd_relatively_prime_bug \
-       pgcd_infinite_loop \
-       exam_cra \
+       exam_chinrem_gcd \
+       exam_function_exvector \
        exam_real_imag
 
+CHECKS = check_numeric \
+        check_inifcns \
+        check_matrices \
+        check_lsolve \
+        check_cra
+
 TIMES = time_dennyfliegner \
        time_gammaseries \
        time_vandermonde \
        time_toeplitz \
-       time_hashmap \
        time_lw_A \
        time_lw_B \
        time_lw_C \
@@ -64,45 +64,33 @@ TIMES = time_dennyfliegner \
        time_uvar_gcd \
        time_parser
 
-TESTS = $(CHECKS) $(EXAMS) $(TIMES)
-check_PROGRAMS = $(CHECKS) $(EXAMS) $(TIMES)
-
-check_numeric_SOURCES = check_numeric.cpp 
-check_numeric_LDADD = ../ginac/libginac.la
-
-check_inifcns_SOURCES = check_inifcns.cpp
-check_inifcns_LDADD = ../ginac/libginac.la
-
-check_matrices_SOURCES = check_matrices.cpp genex.cpp
-check_matrices_LDADD = ../ginac/libginac.la
-
-check_lsolve_SOURCES = check_lsolve.cpp genex.cpp
-check_lsolve_LDADD = ../ginac/libginac.la
-
-check_mul_info_SOURCES = check_mul_info.cpp
-check_mul_info_LDADD = ../ginac/libginac.la
+TESTS = $(EXAMS) $(CHECKS) $(TIMES)
+check_PROGRAMS = $(EXAMS) $(CHECKS) $(TIMES)
 
 exam_paranoia_SOURCES = exam_paranoia.cpp
 exam_paranoia_LDADD = ../ginac/libginac.la
 
-exam_heur_gcd_SOURCES = heur_gcd_bug.cpp 
+exam_heur_gcd_SOURCES = exam_heur_gcd.cpp
 exam_heur_gcd_LDADD = ../ginac/libginac.la
 
-match_bug_SOURCES = match_bug.cpp error_report.h
-match_bug_LDADD = ../ginac/libginac.la
-
-parser_bugs_SOURCES = parser_bugs.cpp
-parser_bugs_LDADD = ../ginac/libginac.la
+exam_match_SOURCES = exam_match.cpp error_report.h
+exam_match_LDADD = ../ginac/libginac.la
 
-exam_numeric_archive_SOURCES = numeric_archive.cpp
-exam_numeric_archive_LDADD = ../ginac/libginac.la
+exam_parser_SOURCES = exam_parser.cpp
+exam_parser_LDADD = ../ginac/libginac.la
 
 exam_numeric_SOURCES = exam_numeric.cpp
 exam_numeric_LDADD = ../ginac/libginac.la
 
+exam_relational_SOURCES = exam_relational.cpp
+exam_relational_LDADD = ../ginac/libginac.la
+
 exam_powerlaws_SOURCES = exam_powerlaws.cpp
 exam_powerlaws_LDADD = ../ginac/libginac.la
 
+exam_collect_SOURCES = exam_collect.cpp
+exam_collect_LDADD = ../ginac/libginac.la
+
 exam_inifcns_SOURCES = exam_inifcns.cpp
 exam_inifcns_LDADD = ../ginac/libginac.la
 
@@ -110,15 +98,24 @@ exam_inifcns_nstdsums_SOURCES = exam_inifcns_nstdsums.cpp \
                                exam_inifcns_nstdsums.h
 exam_inifcns_nstdsums_LDADD = ../ginac/libginac.la
 
+exam_inifcns_elliptic_SOURCES = exam_inifcns_elliptic.cpp
+exam_inifcns_elliptic_LDADD = ../ginac/libginac.la
+
 exam_differentiation_SOURCES = exam_differentiation.cpp
 exam_differentiation_LDADD = ../ginac/libginac.la
 
 exam_polygcd_SOURCES = exam_polygcd.cpp
 exam_polygcd_LDADD = ../ginac/libginac.la
 
+exam_collect_common_factors_SOURCES = exam_collect_common_factors.cpp
+exam_collect_common_factors_LDADD = ../ginac/libginac.la
+
 exam_normalization_SOURCES = exam_normalization.cpp
 exam_normalization_LDADD = ../ginac/libginac.la
 
+exam_sqrfree_SOURCES = exam_sqrfree.cpp
+exam_sqrfree_LDADD = ../ginac/libginac.la
+
 exam_factor_SOURCES = exam_factor.cpp
 exam_factor_LDADD = ../ginac/libginac.la
 
@@ -146,21 +143,39 @@ exam_archive_LDADD = ../ginac/libginac.la
 exam_structure_SOURCES = exam_structure.cpp
 exam_structure_LDADD = ../ginac/libginac.la
 
-exam_hashmap_SOURCES = exam_hashmap.cpp
-exam_hashmap_LDADD = ../ginac/libginac.la
-
 exam_misc_SOURCES = exam_misc.cpp
 exam_misc_LDADD = ../ginac/libginac.la
 
+exam_pgcd_SOURCES = exam_pgcd.cpp
+exam_pgcd_LDADD = ../ginac/libginac.la
+
 exam_mod_gcd_SOURCES = exam_mod_gcd.cpp
 exam_mod_gcd_LDADD = ../ginac/libginac.la
 
-exam_cra_SOURCES = exam_cra.cpp
-exam_cra_LDADD = ../ginac/libginac.la
-
 exam_real_imag_SOURCES = exam_real_imag.cpp
 exam_real_imag_LDADD = ../ginac/libginac.la
 
+exam_chinrem_gcd_SOURCES = exam_chinrem_gcd.cpp
+exam_chinrem_gcd_LDADD = ../ginac/libginac.la
+
+exam_function_exvector_SOURCES = exam_function_exvector.cpp
+exam_function_exvector_LDADD = ../ginac/libginac.la
+
+check_numeric_SOURCES = check_numeric.cpp
+check_numeric_LDADD = ../ginac/libginac.la
+
+check_inifcns_SOURCES = check_inifcns.cpp
+check_inifcns_LDADD = ../ginac/libginac.la
+
+check_matrices_SOURCES = check_matrices.cpp genex.cpp
+check_matrices_LDADD = ../ginac/libginac.la
+
+check_lsolve_SOURCES = check_lsolve.cpp genex.cpp
+check_lsolve_LDADD = ../ginac/libginac.la
+
+check_cra_SOURCES = check_cra.cpp
+check_cra_LDADD = ../ginac/libginac.la
+
 time_dennyfliegner_SOURCES = time_dennyfliegner.cpp \
                             randomize_serials.cpp timer.cpp timer.h
 time_dennyfliegner_LDADD = ../ginac/libginac.la
@@ -176,9 +191,6 @@ time_vandermonde_LDADD = ../ginac/libginac.la
 time_toeplitz_SOURCES = time_toeplitz.cpp \
                        randomize_serials.cpp timer.cpp timer.h
 time_toeplitz_LDADD = ../ginac/libginac.la
-time_hashmap_SOURCES = time_hashmap.cpp \
-                      randomize_serials.cpp timer.cpp timer.h
-time_hashmap_LDADD = ../ginac/libginac.la
 
 time_lw_A_SOURCES = time_lw_A.cpp \
                    randomize_serials.cpp timer.cpp timer.h
@@ -263,18 +275,6 @@ time_parser_SOURCES = time_parser.cpp \
                      randomize_serials.cpp timer.cpp timer.h
 time_parser_LDADD = ../ginac/libginac.la
 
-bugme_chinrem_gcd_SOURCES = bugme_chinrem_gcd.cpp
-bugme_chinrem_gcd_LDADD = ../ginac/libginac.la
-
-factor_univariate_bug_SOURCES = factor_univariate_bug.cpp
-factor_univariate_bug_LDADD = ../ginac/libginac.la
-
-pgcd_relatively_prime_bug_SOURCES = pgcd_relatively_prime_bug.cpp
-pgcd_relatively_prime_bug_LDADD = ../ginac/libginac.la
-
-pgcd_infinite_loop_SOURCES =  pgcd_infinite_loop.cpp
-pgcd_infinite_loop_LDADD =  ../ginac/libginac.la
-
 AM_CPPFLAGS = -I$(srcdir)/../ginac -I../ginac -DIN_GINAC
 
 CLEANFILES = exam.gar
similarity index 98%
rename from check/exam_cra.cpp
rename to check/check_cra.cpp
index c875b4f82a4f33c546e5b086b253c9b35c299be2..e3f86a197eb7badef0de17e77f355fd47debe792 100644 (file)
@@ -3,7 +3,7 @@
  *  Test of Chinese remainder algorithm. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index b775d577fecca8196096ce88c73a4d875fc03d2a..6c212dc469688d229e270aad1143fb13b39db378 100644 (file)
@@ -4,7 +4,7 @@
  *  functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index d09b6e9dda94fe7b30703256480bb9f1ad8dd753..8496b45c7923bd3b55410d19a49d69e8abbf80c4 100644 (file)
@@ -5,7 +5,7 @@
  *  the underlying symbolic manipulations. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index a714523be57da6d64356958f4d886bf0bd249c92..f0e383523f5d6e0073185ff6129436fc89613608 100644 (file)
@@ -5,7 +5,7 @@
  *  manipulations. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/check/check_mul_info.cpp b/check/check_mul_info.cpp
deleted file mode 100644 (file)
index 34652f8..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "ginac.h"
-#include <iostream>
-using namespace GiNaC;
-
-int main(int argc, char** argv)
-{
-       symbol x("x"), y("y");
-       ex e = x*y;
-       if (!e.info(info_flags::indefinite)) {
-               std::cerr << "eek, product of two symbols is NOT indefinite";
-               return 1;
-       }
-       return 0;
-}
index 2904a9695573b1ed80e28e4e7a1f587451c86425..a2b08a9ce3a2bff6c6fd4cead9361cf4f5ef1e3a 100644 (file)
@@ -4,7 +4,7 @@
  *  tests on these numbers like is_integer() etc... */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 47a30d28252b9a867a2e1274ffc83233a542966d..a5db742510e931f4b442032b8821665592473dde 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 198df414c032a258d6e0b6ad3cd674ca8b5499f3..fcc3b7ad8486eacb3d7a10553e66e131ccf9b0f5 100644 (file)
@@ -3,7 +3,7 @@
  *  Here we test GiNaC's archiving system. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -27,12 +27,13 @@ using namespace GiNaC;
 #include <iostream>
 using namespace std;
 
+#include <cln/cln.h>
+
+
 unsigned exam_archive()
 {
        unsigned result = 0;
        
-       cout << "examining archiving system" << flush;
-
        symbol x("x"), y("y"), mu("mu"), dim("dim", "\\Delta");
        ex e, f;
 
@@ -76,7 +77,49 @@ unsigned exam_archive()
        return result;
 }
 
+/** numeric::archive used to fail if the real part of a complex number
+ *  is a rational number and the imaginary part is a floating point one. */
+unsigned numeric_complex_bug()
+{
+       using namespace cln;
+       struct archive_unarchive_check
+       {
+               unsigned operator()(const cl_N& n) const
+               {
+                       ex e = numeric(n);
+                       archive ar;
+                       ar.archive_ex(e, "test");
+                       ex check = ar.unarchive_ex(lst{}, "test");
+                       if (!check.is_equal(e)) {
+                               clog << __FILE__ << ':' << __LINE__ << ": expected: " << e << ", got " << check << endl;
+                               return 1;
+                       }
+                       return 0;
+               }
+       } checker;
+       unsigned result = 0;
+       const cl_I one(1);
+       const cl_R three_fp = cl_float(3.0);
+       std::vector<cl_N> numbers = {
+               complex(one, one),
+               complex(one, three_fp),
+               complex(three_fp, one),
+               complex(three_fp, three_fp)
+       };
+       for (auto & n : numbers) {
+               result += checker(n);
+       }
+       return result;
+}
+
 int main(int argc, char** argv)
 {
-       return exam_archive();
+       unsigned result = 0;
+
+       cout << "examining archiving system" << flush;
+
+       result += exam_archive();  cout << '.' << flush;
+       result += numeric_complex_bug();  cout << '.' << flush;
+
+       return result;
 }
similarity index 96%
rename from check/bugme_chinrem_gcd.cpp
rename to check/exam_chinrem_gcd.cpp
index b3161e8a341d6dbef7fd18a8e41b487f10c1f8cb..b020a71eb715f6b48341dbfbc598545d482afcea 100644 (file)
@@ -1,9 +1,9 @@
-/** @file bugme_chinrem_gcd.cpp
+/** @file exam_chinrem_gcd.cpp
  *
  * A small program exposing historical bug in poly_cra function. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@ static void integer_coeff_braindamage()
 
 int main(int argc, char** argv)
 {
-       cout << "checking for bugs in poly_cra() and friends " << flush;
+       cout << "examining in poly_cra() and friends " << flush;
        check_poly_cra();
        check_extract_integer_content();
        integer_coeff_braindamage();
index b067438bb1edbd310c0b942ed0cf84da4d6debd5..3c90a327e52fe93d48f25e461a95ee449e721ae6 100644 (file)
@@ -3,7 +3,7 @@
  *  Here we test GiNaC's Clifford algebra objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/check/exam_collect.cpp b/check/exam_collect.cpp
new file mode 100644 (file)
index 0000000..65cad59
--- /dev/null
@@ -0,0 +1,152 @@
+/** @file exam_collect.cpp
+ *
+ */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+using namespace std;
+
+// Correctness of .collect(Z[x], x).
+static unsigned exam_collect_1()
+{
+       unsigned result = 0;
+       symbol x("x"), y("y");
+       ex a = (pow(x, 3) - 2*pow(x, 2) + 4*x) * pow(y, 2)
+              + (pow(x, 2) - x - 1) * y
+              + (x + 1);
+       ex b = pow(y, 2) * pow(x, 3)
+              + (y - 2*pow(y, 2)) * pow(x, 2)
+              + (4*pow(y, 2) - y + 1) * x
+              + (1 - y);
+
+       ex a_x = collect(a, x);
+       if (a_x != b) {
+               clog << "collect(" << a << ", " << x << ") erroneously returned "
+                    << a_x << " instead of " << b << endl;
+               ++result;
+       }
+
+       ex b_y = collect(b, y);
+       if (b_y != a) {
+               clog << "collect(" << b << ", " << y << ") erroneously returned "
+                    << b_y << " instead of " << a << endl;
+               ++result;
+       }
+
+       ex amb_x = collect(a - b, x);
+       if (amb_x != 0) {
+               clog << "collect(" << a - b << ", " << x << ") erroneously returned "
+                    << amb_x << " instead of 0" << endl;
+               ++result;
+       }
+
+       ex amb_y = collect(a - b, y);
+       if (amb_y != 0) {
+               clog << "collect(" << a - b << ", " << y << ") erroneously returned "
+                    << amb_y << " instead of 0" << endl;
+               ++result;
+       }
+
+       return result;
+}
+
+// Consistency of .collect(Z[x,y], {x,y}) with .coeff(x).
+static unsigned exam_collect_2()
+{
+       unsigned result = 0;
+       symbol x("x"), y("y"), p("p"), q("q");
+
+       ex e1 = x + y;
+       ex e2 = 1 + p + q;
+       ex a = expand(e1 * e2);
+
+       ex a_x = a.collect(x).coeff(x, 1);
+       if (a_x != e2) {
+               clog << "collect(" << a << ", " << x << ") erroneously returned "
+                    << a_x << " as coefficient of " << x << endl;
+               ++result;
+       }
+
+       ex a_p = a.collect(p).coeff(p, 1);
+       if (a_p != e1) {
+               clog << "collect(" << a << ", " << p << ") erroneously returned "
+                    << a_p << " as coefficient of " << p << endl;
+               ++result;
+       }
+
+       ex a_xy = a.collect(lst{x,y});
+       ex ref = e2*x + e2*y;
+       if (a_xy != ref) {
+               clog << "collect(" << a << ", {" << x << ", " << y << "}) erroneously returned "
+                    << a_xy << " instead of " << ref << endl;
+               ++result;
+       }
+
+       return result;
+}
+
+// Consistency of .collect(Z[f(x)], f(x)) with .coeff(f(x)).
+static unsigned exam_collect_3()
+{
+       unsigned result = 0;
+       symbol x("x"), p("p"), q("q");
+
+       for (unsigned deg = 2; deg < 7; ++deg) {
+
+               ex a1 = expand(pow(p + q + x, deg));
+               a1 = a1.collect(x);
+
+               ex a2 = expand(pow(p + q + sin(x), deg));
+               a2 = a2.collect(sin(x));
+
+               for (unsigned i = 0; i < deg; ++i) {
+                       ex a1_i = a1.coeff(x, i);
+                       ex a2_i = a2.coeff(sin(x), i);
+                       if (!expand(a1_i - a2_i).is_zero()) {
+                               clog << "collect(" << a1 << ",sin(x)) inconsistent with "
+                                       "collect(" << a2 << ",x)" << endl;
+                               ++result;
+                       }
+               }
+       }
+
+       return result;
+}
+
+unsigned exam_collect()
+{
+       unsigned result = 0;
+
+       cout << "examining collect coefficients" << flush;
+
+       result += exam_collect_1();  cout << '.' << flush;
+       result += exam_collect_2();  cout << '.' << flush;
+       result += exam_collect_3();  cout << '.' << flush;
+
+       return result;
+}
+
+int main(int argc, char** argv)
+{
+       return exam_collect();
+}
diff --git a/check/exam_collect_common_factors.cpp b/check/exam_collect_common_factors.cpp
new file mode 100644 (file)
index 0000000..520e0d8
--- /dev/null
@@ -0,0 +1,59 @@
+#include <iostream>
+#include "ginac.h"
+using namespace std;
+using namespace GiNaC;
+
+static unsigned exam_collect_common_factors_simple()
+{
+       unsigned result = 0;
+       symbol a("a"), b("b"), c("c"), x("x"), y("y");
+       ex ei, ef, ref;
+
+       ei = a*x + a*y;
+       ef = collect_common_factors(ei);
+       ref = (x+y)*a;
+       if (ef != ref) {
+               clog << "ERROR: collect_common_factors(" << ei << ") returned "
+                    << ef << ", not " << ref << '.' << endl;
+               ++result;
+       }
+
+       ei = a*x*x + 2*a*x*y + a*y*y;
+       ef = collect_common_factors(ei);
+       ref = a*(x*x + 2*x*y + y*y);
+       if (ef != ref) {
+               clog << "ERROR: collect_common_factors(" << ei << ") returned "
+                    << ef << ", not " << ref << '.' << endl;
+               ++result;
+       }
+
+       return result;
+}
+
+static unsigned exam_collect_common_factors_zero()
+{
+       // r = 0 = c*0 = c*(x + 1 - 1 - x) = c*(x + 1) - c - c*x
+       // e = a*r - b*r
+       symbol a("a"), b("b"), c("c"), x("x");
+
+       ex r = c*(x+1) - c - c*x;
+       ex ei = a*r + b*r;
+       ex ef = collect_common_factors(ei);
+       if (!ef.is_zero()) {
+               clog << "ERROR: " << ei << " should be 0, got " << ef << " instead." << endl;
+               return 1;
+       }
+       return 0;
+}
+
+int main(int argc, char** argv)
+{
+       int result = 0;
+
+       cout << "examining collect_common_factors" << flush;
+
+       result += exam_collect_common_factors_simple();  cout << '.' << flush;
+       result += exam_collect_common_factors_zero();  cout << '.' << flush;
+
+       return result;
+}
index e328589411a67c00dd3bb3d1b1383ee4a7c44122..590cf2dbd5bb60ba7f441b02dc58cfd4e96ade8b 100644 (file)
@@ -3,7 +3,7 @@
  *  Here we test GiNaC's color objects (su(3) Lie algebra). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 1cc41b76893257f38aec11867526ad03af9691fb..39baeafc93dc6a092453469211f2f648b0212b97 100644 (file)
@@ -3,7 +3,7 @@
  *  Tests for symbolic differentiation, including various functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index ce4d7027644ad1b3851b57f4456bc350734b8970..cf1dd06c6b2a41cb2df0113669093f4e5312ad26 100644 (file)
@@ -3,7 +3,7 @@
  *  Factorization test suite. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -26,8 +26,6 @@ using namespace GiNaC;
 #include <iostream>
 using namespace std;
 
-static symbol w("w"), x("x"), y("y"), z("z");
-
 static unsigned check_factor(const ex& e)
 {
        ex ee = e.expand();
@@ -44,9 +42,11 @@ static unsigned exam_factor1()
        unsigned result = 0;
        ex e;
        symbol x("x");
-       lst syms;
-       syms.append(x);
-       
+       lst syms = {x};
+
+       e = 1;
+       result += check_factor(e);
+
        e = ex("1+x-x^3", syms);
        result += check_factor(e);
 
@@ -193,13 +193,30 @@ static unsigned check_factor_expanded(const ex& e)
        return 0;
 }
 
+static unsigned exam_factor_content()
+{
+       unsigned result = 0;
+       ex e;
+       symbol x("x"), y("y");
+
+       // Fixed 2013-07-28 by Alexei Sheplyakov in factor_univariate().
+       e = ex("174247781*x^2-1989199947807987/200000000000000", lst{x});
+       result += check_factor(e);
+
+       // Fixed 2014-05-18 by Alexei Sheplyakov in factor_multivariate().
+       e = ex("(x+y+x*y)*(3*x+2*y)", lst{x, y});
+       result += check_factor(e);
+
+       return result;
+}
+
 static unsigned exam_factor_wang()
 {
        // these 15 polynomials are from the appendix of P.S.Wang,
        // "An Improved Multivariate Polynomial Factoring Algorithm"
        unsigned result = 0;
        ex e;
-       symbol x("x"), y("y"), z("z"), u("u");
+       symbol u("u"), w("w"), x("x"), y("y"), z("z");
 
        e = ex("(z+x*y+10)*(x*z+y+30)*(y*z+x+20)", lst{x, y, z});
        result += check_factor_expanded(e);
@@ -263,31 +280,40 @@ static unsigned exam_factor_wang()
        return result;
 }
 
-static unsigned check_factorization(const exvector& factors)
+static unsigned exam_factor_magerya()
 {
-       ex e = dynallocate<mul>(factors);
-       ex ef = factor(e.expand());
-       if (ef.nops() != factors.size()) {
-               clog << "wrong number of factors, expected " << factors.size() <<
-                       ", got " << ef.nops();
-               return 1;
-       }
-       for (size_t i = 0; i < ef.nops(); ++i) {
-               if (find(factors.begin(), factors.end(), ef.op(i)) == factors.end()) {
-                       clog << "wrong factorization: term not found: " << ef.op(i);
-                       return 1;
-               }
-       }
-       return 0;
-}
+       // In 2017, Vitaly Magerya reported a class of biviariate polynomials
+       // where Hensel lifting sometimes failed to terminate.
+       // https://www.ginac.de/pipermail/ginac-list/2017-December/002162.html
+       unsigned result = 0;
+       ex e;
+       symbol x("x"), y("y");
 
-static unsigned factor_integer_content_bug()
-{
-       parser reader;
-       exvector factors;
-       factors.push_back(reader("x+y+x*y"));
-       factors.push_back(reader("3*x+2*y"));
-       return check_factorization(factors);
+       e = (1+2*x+y)*(1+2*x-y)*(2*x-y)*(2*x+y);
+       result += check_factor_expanded(e);
+
+       e = (7+4*x+y)*(-5+2*x-y)*(-6+6*x+y)*y*(10+2*x+y);
+       result += check_factor_expanded(e);
+
+       e = (8+6*x-y)*(-5+4*x-y)*(-5+6*x+y)*(-2+2*x-y)*(2+4*x+y);
+       result += check_factor_expanded(e);
+
+       e = -(-4+4*x+5*y)*(1+4*x+5*y)*(2+3*y)*(1+2*x-y)*(4+2*x+y);
+       result += check_factor_expanded(e);
+
+       e = (-3+y-2*x)*(4+3*y-4*x)*(3+3*y+2*x)*(-2+3*y+2*x)*(-1+4*y+3*x);
+       result += check_factor_expanded(e);
+
+       e = (-9+7*x+y)*(-5+6*x+y)*(4+2*x+y)*(5+2*x-y)*(7+9*x-y)*(8+6*x-y);
+       result += check_factor_expanded(e);
+
+       e = pow(2*x-y,2)*(-1+6*x-y)*(-1+3*x-y)*(-2+4*x-y)*(1+4*x-y)*(4*x-y)*(2+4*x-y);
+       result += check_factor_expanded(e);
+
+       e = (5+2*y-3*x)*(-4+4*y+3*x)*(-3+4*y-2*x)*(4+5*y-x)*(3*y+2*x)*(-1+3*y+5*x)*(5+3*y+4*x);
+       result += check_factor_expanded(e);
+
+       return result;
 }
 
 unsigned exam_factor()
@@ -299,9 +325,9 @@ unsigned exam_factor()
        result += exam_factor1(); cout << '.' << flush;
        result += exam_factor2(); cout << '.' << flush;
        result += exam_factor3(); cout << '.' << flush;
+       result += exam_factor_content(); cout << '.' << flush;
        result += exam_factor_wang(); cout << '.' << flush;
-       result += factor_integer_content_bug();
-       cout << '.' << flush;
+       result += exam_factor_magerya(); cout << '.' << flush;
 
        return result;
 }
diff --git a/check/exam_function_exvector.cpp b/check/exam_function_exvector.cpp
new file mode 100644 (file)
index 0000000..b5b5d0d
--- /dev/null
@@ -0,0 +1,116 @@
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
+#include "ginac/ginac.h"
+#endif
+
+#include <vector>
+#include <iostream>
+
+using namespace GiNaC;
+using namespace std;
+
+DECLARE_FUNCTION_2P(foobar);
+
+static bool eval_called = false;
+static exvector eval_called_with = {};
+static bool evalf_called = false;
+static exvector evalf_called_with = {};
+
+static void reset() {
+       eval_called_with.clear();
+       evalf_called_with.clear();
+       evalf_called = false;
+       eval_called = false;
+}
+
+static ex foobar_eval(const exvector& args) {
+       eval_called = true;
+       for (auto const& v: args)
+               eval_called_with.push_back(v);
+
+       return foobar(args[0], args[1]).hold();
+}
+
+static ex foobar_evalf(const exvector& args) {
+       evalf_called = true;
+       for (auto const& v: args)
+               evalf_called_with.push_back(v);
+       return foobar(args[0], args[1]).hold();
+}
+
+
+REGISTER_FUNCTION(foobar, eval_func(foobar_eval).
+                         evalf_func(foobar_evalf));
+
+static int check_exvector_eval() {
+       symbol x("x"), y("y");
+       int err = 1;
+
+       reset();
+       ex e = foobar(x, y);
+       if (!eval_called) {
+               clog << "*** Error: " << __func__ << ": foobar_eval hasn't been called" << endl;
+               err *= 2;
+       }
+       if (eval_called_with.size() != 2) {
+               clog << "*** Error: " << __func__ << ": fobar_eval: expected 2 arguments, got " <<
+                       eval_called_with.size() << endl;
+               err *= 3;
+       }
+       if (eval_called_with[0] != x) {
+               clog << "*** Error: " << __func__ << ": fobar_eval: wrong 1st argument, "
+                       "expected " << x << ", got " << eval_called_with[0] << endl;
+               err *= 5;
+       }
+       if (eval_called_with[1] != y) {
+               clog << "*** Error: " << __func__ << ": fobar_eval: wrong 1st argument, "
+                       "expected " << y << ", got " << eval_called_with[1] << endl;
+               err *= 7;
+       }
+       return err - 1;
+}
+
+static int check_exvector_evalf() {
+       int err = 1;
+
+       reset();
+       ex e = foobar(Pi, Euler);
+       e = e.evalf();
+
+       if (!evalf_called) {
+               clog << "*** Error: " << __func__ << ": foobar_evalf hasn't been called" << endl;
+               err *= 2;
+       }
+       if (evalf_called_with.size() != 2) {
+               clog << __func__ << ": foobar_evalf: expected 2 arguments, got " <<
+                       evalf_called_with.size() << endl;
+               err *= 3;
+       }
+       if (!is_a<numeric>(evalf_called_with[0])) {
+               clog << "*** Error: " << __func__ << ": wrong 1st argument of foobar_evalf: "
+                       "expected a real number, got " << evalf_called_with[0] << endl;
+               err *= 5;
+       }
+       if (!is_a<numeric>(evalf_called_with[1])) {
+               clog << "*** Error: " << __func__ << ": wrong 1st argument of foobar_evalf: "
+                       "expected a real number, got " << evalf_called_with[0] << endl;
+               err *= 7;
+       }
+       return err - 1;
+}
+
+int main(int argc, char** argv) {
+       int ret = 0;
+       auto err = check_exvector_evalf();
+       if (err) {
+               ret |= 1;
+               clog << "*** Error " << (err + 1) << " (check_exvector_evalf)" << endl;
+       }
+       err = check_exvector_eval();
+       if (err) { 
+               ret |= 2;
+               clog << "*** Error " << (err + 1) << " (check_exvector_evalf)" << endl;
+       }
+       return ret;
+}
diff --git a/check/exam_hashmap.cpp b/check/exam_hashmap.cpp
deleted file mode 100644 (file)
index ad8c1b2..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/** @file exam_hashmap.cpp
- *
- *  Regression tests for the exhashmap<> container. */
-
-/*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "ginac.h"
-using namespace GiNaC;
-
-#include <iostream>
-using namespace std;
-
-unsigned exam_hashmap()
-{
-       unsigned result = 0;
-       unsigned N = 100;
-
-       cout << "examining hash maps" << flush;
-
-       // Create empty container
-       exhashmap<unsigned> M1;
-       if (M1.size() != 0) {
-               clog << "Newly constructed container has size() != 0" << endl;
-               ++result;
-       }
-       if (!M1.empty()) {
-               clog << "Newly constructed container is not empty" << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Insert elements
-       for (unsigned i = 0; i < N; ++i)
-               M1.insert(make_pair(i, i));
-
-       if (M1.size() != N) {
-               clog << "After " << N << " insertions, size() returns " << M1.size() << " instead of " << N << endl;
-               ++result;
-       }
-
-       for (unsigned i = 0; i < N; ++i) {
-               if (M1[i] != i) {
-                       clog << "Lookup of key " << i << " in M1 didn't return correct value" << endl;
-                       ++result;
-                       break;
-               }
-       }
-
-       if (M1.size() != N) {
-               clog << "After " << N << " lookups, size() returns " << M1.size() << " instead of " << N << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Test constructor from two iterators and operator==
-       exhashmap<unsigned> M2(M1.begin(), M1.end());
-       if (M2.size() != M1.size()) {
-               clog << "Constructor from two iterators: size of destination container (" << M2.size() << ") not equal to size of source (" << M1.size() << ")" << endl;
-               ++result;
-       }
-
-       for (unsigned i = 0; i < N; ++i) {
-               if (M2[i] != i) {
-                       clog << "Lookup of key " << i << " in M2 didn't return correct value" << endl;
-                       ++result;
-                       break;
-               }
-       }
-
-       if (M2 != M1) {
-               clog << "Copied container not equal to source" << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Test assignment operator
-       exhashmap<unsigned> M3;
-       M3 = M1;
-       if (M3.size() != N) {
-               clog << "Assignment operator: size of assigned container not equal to size of original" << endl;
-               ++result;
-       }
-
-       for (unsigned i = 0; i < N; ++i) {
-               if (M3[i] != i) {
-                       clog << "Lookup of key " << i << " in M3 didn't return correct value" << endl;
-                       ++result;
-                       break;
-               }
-       }
-
-       cout << '.' << flush;
-
-       // Test insert(it, it)
-       exhashmap<unsigned> M4;
-       M4.insert(M1.begin(), M1.end());
-
-       if (M4.size() != M1.size()) {
-               clog << "insert(it, it): size of destination container not equal to size of source" << endl;
-               ++result;
-       }
-
-       for (unsigned i = 0; i < N; ++i) {
-               if (M4[i] != i) {
-                       clog << "Lookup of key " << i << " in M4 didn't return correct value" << endl;
-                       ++result;
-                       break;
-               }
-       }
-
-       cout << '.' << flush;
-
-       // Test insert()/find()
-       symbol x("x"), y("y");
-       exhashmap<unsigned> M5;
-       M5.insert(make_pair(x-2, 1));
-       M5.insert(make_pair(sin(x+y), 2));
-       M5.insert(make_pair(Pi, 3));
-       M5.insert(make_pair(0, 4));
-       M5.insert(make_pair(4*pow(x, y), 5));
-       if (M5.size() != 5) {
-               clog << "After 5 insertions, size() returns " << M5.size() << " instead of 5" << endl;
-               ++result;
-       }
-
-       exhashmap<unsigned>::const_iterator cit = M5.find(sin(x+y));
-       if (cit == M5.end()) {
-               clog << "Lookup of sin(x+y) didn't find anything" << endl;
-               ++result;
-       }
-       if (!cit->first.is_equal(sin(x+y))) {
-               clog << "Lookup of sin(x+y) returned an incorrect iterator" << endl;
-               ++result;
-       }
-       if (cit->second != 2) {
-               clog << "Lookup of sin(x+y) returned wrong value" << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Test re-inserting insert()
-       pair<exhashmap<unsigned>::iterator, bool> pit = M5.insert(make_pair(sin(x+y), 42));
-       if (pit.second) {
-               clog << "Reinsertion of sin(x+y) inserted a new value" << endl;
-               ++result;
-       }
-       if (!pit.first->first.is_equal(sin(x+y))) {
-               clog << "Reinsertion of sin(x+y) returned an incorrect iterator" << endl;
-               ++result;
-       }
-       if (pit.first->second != 2) {
-               clog << "Reinsertion of sin(x+y) changed the value" << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Test operator[]
-       unsigned v = M5[sin(x+y)];
-       if (M5.size() != 5) {
-               clog << "operator[] with an existing key changed the container size" << endl;
-               ++result;
-       }
-       if (v != 2) {
-               clog << "operator[] with an existing key returned the wrong value" << endl;
-               ++result;
-       }
-
-       v = M5[y+1];
-       if (M5.size() != 6) {
-               clog << "operator[] with a new key didn't insert a new value" << endl;
-               ++result;
-       }
-       if (v != 0) {
-               clog << "operator[] with a new key returned the wrong value" << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Test erase()
-       exhashmap<unsigned>::iterator it = M5.find(y+1);
-       if (it == M5.end()) {
-               clog << "Key y+1 wasn't found" << endl;
-               ++result;
-       }
-       if (!it->first.is_equal(y+1)) {
-               clog << "find() returned an incorrect iterator" << endl;
-               ++result;
-       }
-       if (it->second != 0) {
-               clog << "find() returned an incorrect value" << endl;
-               ++result;
-       }
-
-       M5.erase(it);
-       if (M5.size() != 5) {
-               clog << "erase(it) didn't reduce the size of the container" << endl;
-               ++result;
-       }
-
-       it = M5.find(y+1);
-       if (it != M5.end()) {
-               clog << "Key was still found after erase()" << endl;
-               ++result;
-       }
-
-       exhashmap<unsigned>::size_type n = M5.erase(Pi);
-       if (n != 1) {
-               clog << "erase(Pi) returned " << n << " instead of 1" << endl;
-               ++result;
-       }
-       if (M5.size() != 4) {
-               clog << "erase(Pi) didn't reduce the size of the container" << endl;
-               ++result;
-       }
-
-       n = M5.erase(42);
-       if (n != 0) {
-               clog << "erase(42) returned " << n << " instead of 0" << endl;
-               ++result;
-       }
-       if (M5.size() != 4) {
-               clog << "erase(42) reduced the size of the container" << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Test swap()
-       exhashmap<unsigned> M6;
-       M6.swap(M1);
-       if (M6.size() != N) {
-               clog << "After swap, size() returns " << M6.size() << " instead of " << N << endl;
-               ++result;
-       }
-       if (M1.size() != 0) {
-               clog << "After swap with empty container, size() returns " << M1.size() << " instead of 0" << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Test clear()
-       M2.clear();
-       if (M2.size() != 0) {
-               clog << "Size of cleared container is " << M5.size() << " instead of 0" << endl;
-               ++result;
-       }
-
-       cout << '.' << flush;
-
-       // Test count()
-       n = M5.count(Pi);
-       if (n != 0) {
-               clog << "count(Pi) returns " << n << " instead of 0" << endl;
-               ++result;
-       }
-
-       n = M5.count(4*pow(x, y));
-       if (n != 1) {
-               clog << "count(4*x^y) returns " << n << " instead of 1" << endl;
-               ++result;
-       }
-       cout << '.' << flush;
-
-       return result;
-}
-
-int main(int argc, char** argv)
-{
-       return exam_hashmap();
-}
similarity index 90%
rename from check/heur_gcd_bug.cpp
rename to check/exam_heur_gcd.cpp
index 40db72cc21d89fec7eee098e988e8aeb8f5a0955..064a4339b83261b5da53e6d8862229f3b471f948 100644 (file)
@@ -1,13 +1,13 @@
 /** @file heur_gcd_bug.cpp
  *
- *  heur_gcd_oops.cpp Check for a bug in heur_gcd().
+ *  exam_heur_gcd.cpp Check for a bug in heur_gcd().
  *
  *  heur_gcd() did not check if the arguments are integer polynomials
  *  (and did not convert them to integer polynomials), which lead to
  *  endless loop or (even worse) wrong result. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ using namespace std;
 
 int main(int argc, char** argv)
 {
-       cout << "checking if heur_gcd() can cope with rational polynomials. ";
+       cout << "examining if heur_gcd() can cope with rational polynomials. ";
        const symbol x("x");
        const ex _ex1(1);
        ex a1 = x + numeric(5, 4);
index 34dde3b203240ac1c66f29468ba2ffd4d6b6b762..602095109246061af41839c64aa302417e1e74bb 100644 (file)
@@ -3,7 +3,7 @@
  *  Here we test manipulations on GiNaC's indexed objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 667d08426aa2288648bf016ce0449159cf03a3ce..a2c6a933f04d81291c590f4db526efc7afc6ee13 100644 (file)
@@ -4,7 +4,7 @@
  *  functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/check/exam_inifcns_elliptic.cpp b/check/exam_inifcns_elliptic.cpp
new file mode 100644 (file)
index 0000000..7e79d96
--- /dev/null
@@ -0,0 +1,419 @@
+/** @file exam_inifcns_nstdsums.cpp
+ *
+ *  This test routine applies assorted tests on initially known higher level
+ *  functions. */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+#include <fstream>
+using namespace std;
+
+
+static unsigned check_q_expansion()
+{
+       unsigned err = 0;
+
+       symbol q("q");
+       int order = 200;
+
+       ex res;
+
+       // q-expansions from Sage up to order 200
+       // notation Ek_N_|a|_|b|_K
+       ex E1_12_1_4_1 = pow(q,2)+pow(q,4)+2*pow(q,5)+pow(q,8)+pow(q,9)+2*pow(q,10)+2*pow(q,13)+pow(q,16)+2*pow(q,17)+pow(q,18)+2*pow(q,20)+3*pow(q,25)+2*pow(q,26)
+               +2*pow(q,29)+pow(q,32)+2*pow(q,34)+pow(q,36)+2*pow(q,37)+2*pow(q,40)+2*pow(q,41)+2*pow(q,45)+pow(q,49)+3*pow(q,50)+2*pow(q,52)+2*pow(q,53)+2*pow(q,58)
+               +2*pow(q,61)+pow(q,64)+4*pow(q,65)+2*pow(q,68)+pow(q,72)+2*pow(q,73)+2*pow(q,74)+2*pow(q,80)+pow(q,81)+2*pow(q,82)+4*pow(q,85)+2*pow(q,89)+2*pow(q,90)
+               +2*pow(q,97)+pow(q,98)+3*pow(q,100)+2*pow(q,101)+2*pow(q,104)+2*pow(q,106)+2*pow(q,109)+2*pow(q,113)+2*pow(q,116)+2*pow(q,117)+pow(q,121)+2*pow(q,122)
+               +4*pow(q,125)+pow(q,128)+4*pow(q,130)+2*pow(q,136)+2*pow(q,137)+pow(q,144)+4*pow(q,145)+2*pow(q,146)+2*pow(q,148)+2*pow(q,149)+2*pow(q,153)+2*pow(q,157)
+               +2*pow(q,160)+pow(q,162)+2*pow(q,164)+3*pow(q,169)+4*pow(q,170)+2*pow(q,173)+2*pow(q,178)+2*pow(q,180)+2*pow(q,181)+4*pow(q,185)+2*pow(q,193)
+               +2*pow(q,194)+pow(q,196)+2*pow(q,197)+numeric(1,4)+q;
+
+       ex E1_12_1_4_3 = numeric(1,4)+pow(q,3)+pow(q,6)+pow(q,12)+2*pow(q,15)+pow(q,24)+pow(q,27)+2*pow(q,30)+2*pow(q,39)+pow(q,48)+2*pow(q,51)+pow(q,54)+2*pow(q,60)
+               +3*pow(q,75)+2*pow(q,78)+2*pow(q,87)+pow(q,96)+2*pow(q,102)+pow(q,108)+2*pow(q,111)+2*pow(q,120)+2*pow(q,123)+2*pow(q,135)+pow(q,147)+3*pow(q,150)
+               +2*pow(q,156)+2*pow(q,159)+2*pow(q,174)+2*pow(q,183)+pow(q,192)+4*pow(q,195);
+
+       ex E1_12_1_3_1 = 2*pow(q,175)+2*pow(q,189)+2*pow(q,199)+numeric(1,6)+2*pow(q,129)+4*pow(q,133)+2*pow(q,139)+2*pow(q,151)+2*pow(q,163)+2*pow(q,171)+2*pow(q,172)
+               +2*pow(q,31)+2*pow(q,43)+2*pow(q,57)+2*pow(q,63)+2*pow(q,67)+2*pow(q,76)+2*pow(q,79)+2*pow(q,84)+4*pow(q,91)+2*pow(q,93)+2*pow(q,103)+2*pow(q,112)
+               +2*pow(q,124)+2*pow(q,127)+pow(q,4)+pow(q,9)+2*pow(q,13)+pow(q,16)+pow(q,25)+pow(q,36)+2*pow(q,37)+3*pow(q,49)+2*pow(q,52)+2*pow(q,61)+pow(q,64)
+               +2*pow(q,73)+pow(q,81)+2*pow(q,97)+pow(q,100)+2*pow(q,109)+2*pow(q,117)+pow(q,121)+pow(q,144)+2*pow(q,148)+2*pow(q,157)+3*pow(q,169)+2*pow(q,181)
+               +2*pow(q,193)+3*pow(q,196)+pow(q,3)+pow(q,12)+pow(q,27)+2*pow(q,39)+pow(q,48)+pow(q,75)+pow(q,108)+2*pow(q,111)+3*pow(q,147)+2*pow(q,156)+2*pow(q,183)
+               +pow(q,192)+2*pow(q,7)+2*pow(q,19)+2*pow(q,21)+2*pow(q,28)+q;
+
+       ex E1_12_1_3_2 = numeric(1,6)+pow(q,2)+pow(q,8)+pow(q,18)+2*pow(q,26)+pow(q,32)+pow(q,50)+pow(q,72)+2*pow(q,74)+3*pow(q,98)+2*pow(q,104)+2*pow(q,122)+pow(q,128)
+               +2*pow(q,146)+pow(q,162)+2*pow(q,194)+pow(q,6)+pow(q,24)+pow(q,54)+2*pow(q,78)+pow(q,96)+pow(q,150)+2*pow(q,14)+2*pow(q,38)+2*pow(q,42)+2*pow(q,56)
+               +2*pow(q,62)+2*pow(q,86)+2*pow(q,114)+2*pow(q,126)+2*pow(q,134)+2*pow(q,152)+2*pow(q,158)+2*pow(q,168)+4*pow(q,182)+2*pow(q,186);
+
+       ex E1_12_1_3_4 = numeric(1,6)+pow(q,4)+pow(q,12)+pow(q,16)+2*pow(q,28)+pow(q,36)+pow(q,48)+2*pow(q,52)+pow(q,64)+2*pow(q,76)+2*pow(q,84)+pow(q,100)+pow(q,108)
+               +2*pow(q,112)+2*pow(q,124)+pow(q,144)+2*pow(q,148)+2*pow(q,156)+2*pow(q,172)+pow(q,192)+3*pow(q,196);
+
+
+       ex E2_12_1_1_2 = 248*pow(q,175)+320*pow(q,189)+200*pow(q,199)+176*pow(q,129)+160*pow(q,133)+140*pow(q,139)+152*pow(q,151)+164*pow(q,163)+260*pow(q,171)
+               +44*pow(q,172)+32*pow(q,31)+44*pow(q,43)+80*pow(q,57)+104*pow(q,63)+68*pow(q,67)+20*pow(q,76)+80*pow(q,79)+32*pow(q,84)+112*pow(q,91)+128*pow(q,93)
+               +104*pow(q,103)+8*pow(q,112)+32*pow(q,124)+128*pow(q,127)+pow(q,2)+pow(q,4)+6*pow(q,5)+pow(q,8)+13*pow(q,9)+6*pow(q,10)+14*pow(q,13)+pow(q,16)
+               +18*pow(q,17)+13*pow(q,18)+6*pow(q,20)+31*pow(q,25)+14*pow(q,26)+30*pow(q,29)+pow(q,32)+18*pow(q,34)+13*pow(q,36)+38*pow(q,37)+6*pow(q,40)+42*pow(q,41)
+               +78*pow(q,45)+57*pow(q,49)+31*pow(q,50)+14*pow(q,52)+54*pow(q,53)+30*pow(q,58)+62*pow(q,61)+pow(q,64)+84*pow(q,65)+18*pow(q,68)+13*pow(q,72)+74*pow(q,73)
+               +38*pow(q,74)+6*pow(q,80)+121*pow(q,81)+42*pow(q,82)+108*pow(q,85)+90*pow(q,89)+78*pow(q,90)+98*pow(q,97)+57*pow(q,98)+31*pow(q,100)+102*pow(q,101)
+               +14*pow(q,104)+54*pow(q,106)+110*pow(q,109)+114*pow(q,113)+30*pow(q,116)+182*pow(q,117)+133*pow(q,121)+62*pow(q,122)+156*pow(q,125)+pow(q,128)+84*pow(q,130)
+               +18*pow(q,136)+138*pow(q,137)+13*pow(q,144)+180*pow(q,145)+74*pow(q,146)+38*pow(q,148)+150*pow(q,149)+234*pow(q,153)+158*pow(q,157)+6*pow(q,160)+121*pow(q,162)
+               +42*pow(q,164)+183*pow(q,169)+108*pow(q,170)+174*pow(q,173)+90*pow(q,178)+78*pow(q,180)+182*pow(q,181)+228*pow(q,185)+194*pow(q,193)+98*pow(q,194)+57*pow(q,196)
+               +198*pow(q,197)+4*pow(q,3)+4*pow(q,6)+4*pow(q,12)+24*pow(q,15)+4*pow(q,24)+40*pow(q,27)+24*pow(q,30)+56*pow(q,39)+4*pow(q,48)+72*pow(q,51)+40*pow(q,54)
+               +24*pow(q,60)+124*pow(q,75)+56*pow(q,78)+120*pow(q,87)+4*pow(q,96)+72*pow(q,102)+40*pow(q,108)+152*pow(q,111)+24*pow(q,120)+168*pow(q,123)+240*pow(q,135)
+               +228*pow(q,147)+124*pow(q,150)+56*pow(q,156)+216*pow(q,159)+120*pow(q,174)+248*pow(q,183)+4*pow(q,192)+336*pow(q,195)+8*pow(q,7)+20*pow(q,19)+32*pow(q,21)
+               +8*pow(q,28)+8*pow(q,14)+20*pow(q,38)+32*pow(q,42)+8*pow(q,56)+32*pow(q,62)+44*pow(q,86)+80*pow(q,114)+104*pow(q,126)+68*pow(q,134)+20*pow(q,152)+80*pow(q,158)
+               +32*pow(q,168)+112*pow(q,182)+128*pow(q,186)+12*pow(q,11)+12*pow(q,22)+24*pow(q,23)+48*pow(q,33)+48*pow(q,35)+12*pow(q,44)+24*pow(q,46)+48*pow(q,47)+72*pow(q,55)
+               +60*pow(q,59)+48*pow(q,66)+96*pow(q,69)+48*pow(q,70)+72*pow(q,71)+96*pow(q,77)+84*pow(q,83)+12*pow(q,88)+24*pow(q,92)+48*pow(q,94)+120*pow(q,95)+156*pow(q,99)
+               +192*pow(q,105)+108*pow(q,107)+72*pow(q,110)+144*pow(q,115)+60*pow(q,118)+144*pow(q,119)+132*pow(q,131)+48*pow(q,132)+96*pow(q,138)+48*pow(q,140)+192*pow(q,141)
+               +72*pow(q,142)+168*pow(q,143)+96*pow(q,154)+192*pow(q,155)+192*pow(q,161)+288*pow(q,165)+84*pow(q,166)+168*pow(q,167)+12*pow(q,176)+240*pow(q,177)+180*pow(q,179)
+               +24*pow(q,184)+216*pow(q,187)+48*pow(q,188)+120*pow(q,190)+192*pow(q,191)+156*pow(q,198)+numeric(1,24)+q;
+
+       ex E3_12_3_1_4 = 1850*pow(q,172)+362*pow(q,76)+450*pow(q,84)+650*pow(q,112)+962*pow(q,124)+pow(q,4)+3*pow(q,8)+13*pow(q,16)+24*pow(q,20)+51*pow(q,32)+81*pow(q,36)
+               +72*pow(q,40)+170*pow(q,52)+205*pow(q,64)+288*pow(q,68)+243*pow(q,72)+312*pow(q,80)+601*pow(q,100)+510*pow(q,104)+840*pow(q,116)+819*pow(q,128)+864*pow(q,136)
+               +1053*pow(q,144)+1370*pow(q,148)+1224*pow(q,160)+1680*pow(q,164)+1944*pow(q,180)+2451*pow(q,196)+9*pow(q,12)+27*pow(q,24)+117*pow(q,48)+216*pow(q,60)
+               +459*pow(q,96)+729*pow(q,108)+648*pow(q,120)+1530*pow(q,156)+1845*pow(q,192)+50*pow(q,28)+150*pow(q,56)+1086*pow(q,152)+1350*pow(q,168)+120*pow(q,44)
+               +360*pow(q,88)+528*pow(q,92)+1080*pow(q,132)+1200*pow(q,140)+1560*pow(q,176)+1584*pow(q,184)+2208*pow(q,188);
+
+       // basis of Eisenstein space for Gamma_1(12) of weight 1
+       res =  series_to_poly(Eisenstein_kernel(1, 12, 1, -3, 1).q_expansion_modular_form(q, order)) - E1_12_1_3_1;
+       if ( res != 0 ) err++;
+
+       res =  series_to_poly(Eisenstein_kernel(1, 12, 1, -3, 2).q_expansion_modular_form(q, order)) - E1_12_1_3_2;
+       if ( res != 0 ) err++;
+
+       res =  series_to_poly(Eisenstein_kernel(1, 12, 1, -3, 4).q_expansion_modular_form(q, order)) - E1_12_1_3_4;
+       if ( res != 0 ) err++;
+
+       res =  series_to_poly(Eisenstein_kernel(1, 12, 1, -4, 1).q_expansion_modular_form(q, order)) - E1_12_1_4_1;
+       if ( res != 0 ) err++;
+
+       res =  series_to_poly(Eisenstein_kernel(1, 12, 1, -4, 3).q_expansion_modular_form(q, order)) - E1_12_1_4_3;
+       if ( res != 0 ) err++;
+
+       // test one series of weight 2
+       res =  series_to_poly(Eisenstein_kernel(2, 12, 1, 1, 2).q_expansion_modular_form(q, order)) - E2_12_1_1_2;
+       if ( res != 0 ) err++;
+
+       // and one of weight 3
+       res =  series_to_poly(Eisenstein_kernel(3, 12, -3, 1, 4).q_expansion_modular_form(q, order)) - E3_12_3_1_4;
+       if ( res != 0 ) err++;
+
+       return err;
+}
+
+static unsigned check_polylogs()
+{
+       unsigned err = 0;
+
+       int digitsbuf = Digits;
+       Digits = 100;
+       ex prec = 5 * pow(10, -(ex)Digits);
+
+       ex y = numeric(9,10);
+
+       ex z2 = numeric(2);
+       ex z3 = numeric(3);
+
+       ex L0 =  basic_log_kernel();
+       ex omega_2 = multiple_polylog_kernel(z2);
+       ex omega_3 = multiple_polylog_kernel(z3);
+
+       ex res1,res2;
+
+       res1 = G(lst{z2},y).evalf();
+       res2 = iterated_integral(lst{omega_2},y).evalf();
+       if ( abs(res1-res2) > prec ) err++;
+
+       res1 = G(lst{0},y).evalf();
+       res2 = iterated_integral(lst{L0},y).evalf();
+       if ( abs(res1-res2) > prec ) err++;
+
+       res1 = G(lst{z2,0},y).evalf();
+       res2 = iterated_integral(lst{omega_2,L0},y).evalf();
+       if ( abs(res1-res2) > prec ) err++;
+
+       res1 = G(lst{0,0},y).evalf();
+       res2 = iterated_integral(lst{L0,L0},y).evalf();
+       if ( abs(res1-res2) > prec ) err++;
+
+       res1 = G(lst{z2,0,0},y).evalf();
+       res2 = iterated_integral(lst{omega_2,L0,L0},y).evalf();
+       if ( abs(res1-res2) > prec ) err++;
+
+       Digits = digitsbuf;
+
+       return err;
+}
+
+static unsigned check_iterated_integral_modular_form_versus_Kronecker_dtau()
+{
+       unsigned err = 0;
+
+       int digitsbuf = Digits;
+       Digits = 30;
+       ex prec = 5 * pow(10, -(ex)Digits);
+
+       ex tau_6 = I;
+       ex qbar_6 = exp(2*Pi*I*tau_6);
+       ex omega_0 = basic_log_kernel();
+
+       ex eta_1   = Eisenstein_kernel(3, 6, -3, 1, 1);
+       ex eta_2   = Eisenstein_kernel(3, 6, -3, 1, 2);
+       ex omega_3 = modular_form_kernel(3, eta_1-8*eta_2);
+       ex res1 = iterated_integral(lst{omega_0,omega_3},qbar_6).evalf();
+
+       ex C_3  = I/sqrt(numeric(3));
+       ex g3_1 = Kronecker_dtau_kernel(3,numeric(1,3),1,C_3);
+       ex g3_2 = Kronecker_dtau_kernel(3,numeric(1,3),2,C_3);
+       ex expr = iterated_integral(lst{omega_0,g3_1},qbar_6) - 4*iterated_integral(lst{omega_0,g3_2},qbar_6);
+       ex res2 = expr.evalf();
+
+       if ( abs(res1-res2) > prec ) err++;
+
+       Digits = digitsbuf;
+
+       return err;
+}
+
+static unsigned check_modular_trafo()
+{
+       unsigned err = 0;
+
+       int digitsbuf = Digits;
+       Digits = 50;
+       ex prec = 5 * pow(10, -(ex)Digits);
+
+       int N_trunc = 100;
+
+       int a = 0;
+       int b = -1;
+       int c = 1;
+       int d = 0;
+
+       ex tau = numeric(1,10)+numeric(4,5)*I;
+       ex qbar = evalf(exp(2*Pi*I*tau));
+       ex qbar_2 = evalf(exp(2*Pi*I*tau*numeric(1,2)));
+       ex qbar_3 = evalf(exp(2*Pi*I*tau*numeric(1,3)));
+       ex qbar_4 = evalf(exp(2*Pi*I*tau*numeric(1,4)));
+       ex qbar_6 = evalf(exp(2*Pi*I*tau*numeric(1,6)));
+       ex qbar_12 = evalf(exp(2*Pi*I*tau*numeric(1,12)));
+
+       ex tau_prime = (a*tau+b)/(c*tau+d);
+       ex qbar_prime = evalf(exp(2*Pi*I*tau_prime));
+       ex qbar_prime_2 = evalf(exp(2*Pi*I*tau_prime*numeric(1,2)));
+       ex qbar_prime_3 = evalf(exp(2*Pi*I*tau_prime*numeric(1,3)));
+       ex qbar_prime_4 = evalf(exp(2*Pi*I*tau_prime*numeric(1,4)));
+       ex qbar_prime_6 = evalf(exp(2*Pi*I*tau_prime*numeric(1,6)));
+       ex qbar_prime_12 = evalf(exp(2*Pi*I*tau_prime*numeric(1,12)));
+
+       numeric k,N,r,s;
+       ex eta,eta_trafo,res1,res2;
+
+       k = 4;
+       N = 1;
+       eta = Eisenstein_kernel(k, N, 1, 1, 1);
+       res1 = ex_to<Eisenstein_kernel>(eta).get_numerical_value(qbar_prime,N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_kernel>(eta).get_numerical_value(qbar,N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 4;
+       N = 2;
+       r = 0;
+       s = 0;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_2,N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_2,N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 4;
+       N = 2;
+       r = 1;
+       s = 1;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_2,N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_2,N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 4;
+       N = 4;
+       r = 2;
+       s = 2;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_4,N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_4,N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 4;
+       N = 6;
+       r = 3;
+       s = 3;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_6,3*N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_6,3*N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 4;
+       N = 12;
+       r = 6;
+       s = 6;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_12,6*N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_12,6*N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 4;
+       N = 2;
+       r = 1;
+       s = 0;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_2,N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_2,N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 6;
+       N = 6;
+       r = 1;
+       s = 5;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_6,2*N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_6,2*N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 6;
+       N = 12;
+       r = 2;
+       s = 10;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_12,4*N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_12,4*N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 4;
+       N = 3;
+       r = 1;
+       s = 2;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_3,N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_3,N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       k = 1;
+       N = 6;
+       r = 1;
+       s = 5;
+       eta       = Eisenstein_h_kernel(k, N, r, s);
+       eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+       res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_6,2*N_trunc);
+       res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_6,2*N_trunc);
+       if ( abs(res1-res2) > prec ) err++;
+
+       Digits = digitsbuf;
+
+       return err;
+}
+
+static unsigned check_Kronecker_g()
+{
+       unsigned err = 0;
+
+       int digitsbuf = Digits;
+       Digits = 20;
+       ex prec = 5 * pow(10, -(ex)Digits);
+
+       ex tau = numeric(1,10)+numeric(2)*I;
+       ex qbar = evalf(exp(2*Pi*I*tau));
+
+       ex z = numeric(2,100)+numeric(1,10)*I;
+       ex wbar = evalf(exp(2*Pi*I*z));
+
+       ex z_j = numeric(-1,10)*I;
+
+       ex res1,res2,res3;
+
+       res1 = Kronecker_dtau_kernel(0,z).get_numerical_value(qbar);
+       res2 = Kronecker_dz_kernel(1,0,tau).get_numerical_value(z);
+       res3 = Kronecker_dz_kernel(1,z_j,tau).get_numerical_value(z+z_j);
+       if ( abs(res1-res2) > prec ) err++;
+       if ( abs(res1-res3) > prec ) err++;
+
+       res1 = Kronecker_dtau_kernel(1,z).get_numerical_value(qbar);
+       res2 = Kronecker_dz_kernel(2,0,tau).get_numerical_value(z);
+       res3 = Kronecker_dz_kernel(2,z_j,tau).get_numerical_value(z+z_j);
+       if ( abs(res1-res2) > prec ) err++;
+       if ( abs(res1-res3) > prec ) err++;
+
+       res1 = Kronecker_dtau_kernel(2,z).get_numerical_value(qbar);
+       res2 = Kronecker_dz_kernel(3,0,tau).get_numerical_value(z);
+       res3 = Kronecker_dz_kernel(3,z_j,tau).get_numerical_value(z+z_j);
+       if ( abs(res1-res2) > prec ) err++;
+       if ( abs(res1-res3) > prec ) err++;
+    
+       res1 = Kronecker_dtau_kernel(3,z).get_numerical_value(qbar);
+       res2 = Kronecker_dz_kernel(4,0,tau).get_numerical_value(z);
+       res3 = Kronecker_dz_kernel(4,z_j,tau).get_numerical_value(z+z_j);
+       if ( abs(res1-res2) > prec ) err++;
+       if ( abs(res1-res3) > prec ) err++;
+    
+       res1 = Kronecker_dtau_kernel(4,z).get_numerical_value(qbar);
+       res2 = Kronecker_dz_kernel(5,0,tau).get_numerical_value(z);
+       res3 = Kronecker_dz_kernel(5,z_j,tau).get_numerical_value(z+z_j);
+       if ( abs(res1-res2) > prec ) err++;
+       if ( abs(res1-res3) > prec ) err++;
+    
+       res1 = Kronecker_dtau_kernel(5,z).get_numerical_value(qbar);
+       res2 = Kronecker_dz_kernel(6,0,tau).get_numerical_value(z);
+       res3 = Kronecker_dz_kernel(6,z_j,tau).get_numerical_value(z+z_j);
+       if ( abs(res1-res2) > prec ) err++;
+       if ( abs(res1-res3) > prec ) err++;
+
+       Digits = digitsbuf;
+
+       return err;
+}
+
+unsigned exam_inifcns_elliptic(void)
+{
+       unsigned result = 0;
+       
+       cout << "examining consistency of iterated integrals" << flush;
+       
+       result += check_q_expansion();
+       result += check_polylogs();
+       result += check_iterated_integral_modular_form_versus_Kronecker_dtau();
+       result += check_modular_trafo();
+       result += check_Kronecker_g();
+       
+       return result;
+}
+
+int main(int argc, char** argv)
+{
+       return exam_inifcns_elliptic();
+}
index 86c6416bb97c4b7bd3b74eee80095fe5fc40ebf7..5b1baf6b37552561989a3bfb716228fad2ae7f45 100644 (file)
@@ -4,7 +4,7 @@
  *  functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -128,7 +128,8 @@ static unsigned inifcns_test_HLi()
        using GiNaC::log;
        int digitsbuf = Digits;
        Digits = 17;
-       ex prec = 5 * pow(10, -(ex)Digits);
+       // 15.01.2022: prec set to 10*pow(10,-Digits) to avoid exam failure in sporadic cases
+       ex prec = 10 * pow(10, -(ex)Digits);
        numeric almostone("0.999999999999999999");
        unsigned result = 0;
 
index 272b15b4bbe009ca92602d2e21b0625d4310874a..60e2fe3460550f7acfcf9149defb1c6e272fa5be 100644 (file)
@@ -3,7 +3,7 @@
  *  Comparison data for the test of polylogarithms. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 422f7be5a02fc757e3ff4fddcfa04edf917392f3..6da7a7b971119fb457901b6ffd84d1760dcda9d1 100644 (file)
@@ -3,7 +3,7 @@
  *  These exams test solving small linear systems of symbolic equations. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
similarity index 93%
rename from check/match_bug.cpp
rename to check/exam_match.cpp
index c0181baafac59a39a5c373246fab5df84db5711a..f71ec4d45f7adde68ece84d20f6c51204c9af0d8 100644 (file)
@@ -1,10 +1,10 @@
-/** @file match_bug.cpp
+/** @file exam_match.cpp
  *
  *  Check for bug in GiNaC::ex::match() described here:
- *  http://www.ginac.de/pipermail/ginac-devel/2006-April/000942.html */
+ *  https://www.ginac.de/pipermail/ginac-devel/2006-April/000942.html */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ using namespace GiNaC;
  * could be modified even if the match failed! Although this "feature"
  * was documented it happened to be very confusing *even for GiNaC
  * developers*, see 
- * http://www.ginac.de/pipermail/ginac-devel/2006-April/000942.html
+ * https://www.ginac.de/pipermail/ginac-devel/2006-April/000942.html
  *
  * It was fixed in 192ed7390b7b2b705ad100e3db0a92eedd2b20ad. Let's make
  * sure it will be never re-added:
@@ -117,7 +117,7 @@ static void expairseq_match_false_negative(int count)
 int main(int argc, char** argv)
 {
        const int repetitions = 100;
-       std::cout << "checking for historical bugs in match()... " << std::flush;
+       std::cout << "examining historical bugs in match()... " << std::flush;
        failed_match_have_side_effects();
        match_false_negative();
        expairseq_failed_match_no_side_effect(repetitions);
index b163386fe4f22b5d3e8af952f16401649637b65d..1d5b081769e2fc53b5bc4333c4d75a012cf173f5 100644 (file)
@@ -4,7 +4,7 @@
  *  Here we examine manipulations on GiNaC's symbolic matrices. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -367,7 +367,7 @@ static unsigned matrix_misc()
        bool caught = false;
        try {
                m5 = inverse(m4);
-       } catch (std::runtime_error err) {
+       } catch (std::runtime_error &err) {
                caught = true;
        }
        if (!caught) {
index 13152f2707ed183e281c2758b4e07f62b7385d5d..31e0e9e21e3a62b1b80665e733375e5c73ea3787 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -89,49 +89,6 @@ static unsigned exam_expand_power()
        return result;
 }
 
-static unsigned exam_sqrfree()
-{
-       unsigned result = 0;
-       symbol x("x"), y("y");
-       ex e1, e2;
-       
-       e1 = (1+x)*pow((2+x),2)*pow((3+x),3)*pow((4+x),4);
-       e2 = sqrfree(expand(e1),lst{x});
-       if (e1 != e2) {
-               clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
-                    << e2 << endl;
-               ++result;
-       }
-       
-       e1 = (x+y)*pow((x+2*y),2)*pow((x+3*y),3)*pow((x+4*y),4);
-       e2 = sqrfree(expand(e1));
-       if (e1 != e2) {
-               clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
-                    << e2 << endl;
-               ++result;
-       }
-       e2 = sqrfree(expand(e1),lst{x});
-       if (e1 != e2) {
-               clog << "sqrfree(expand(" << e1 << "),[x]) erroneously returned "
-                    << e2 << endl;
-               ++result;
-       }
-       e2 = sqrfree(expand(e1),lst{y});
-       if (e1 != e2) {
-               clog << "sqrfree(expand(" << e1 << "),[y]) erroneously returned "
-                    << e2 << endl;
-               ++result;
-       }
-       e2 = sqrfree(expand(e1),lst{x,y});
-       if (e1 != e2) {
-               clog << "sqrfree(expand(" << e1 << "),[x,y]) erroneously returned "
-                    << e2 << endl;
-               ++result;
-       }
-       
-       return result;
-}
-
 /* Arithmetic Operators should behave just as one expects from built-in types.
  * When somebody screws up the operators this routine will most probably fail
  * to compile.  Unfortunately we can only test the stuff that is allowed, not
@@ -235,6 +192,24 @@ static unsigned exam_subs()
                ++result;
        }
 
+       // This used to fail in GiNaC 1.8.2 with subs_options::no_pattern
+       e1 = 1/x;
+       e2 = e1.subs(x == 1/x);
+       if (!e2.is_equal(x)) {
+               clog << "(1/x).subs(x==1/x) erroneously returned " << e2 << " instead of x" << endl;
+               ++result;
+       }
+       e2 = e1.subs(x == 1/x, subs_options::no_pattern);
+       if (!e2.is_equal(x)) {
+               clog << "(1/x).subs(x==1/x, subs_options::no_pattern) erroneously returned " << e2 << " instead of x" << endl;
+               ++result;
+       }
+       e2 = e1.subs(x == 1/x, subs_options::algebraic);
+       if (!e2.is_equal(x)) {
+               clog << "(1/x).subs(x==1/x, subs_options::algebraic) erroneously returned " << e2 << " instead of x" << endl;
+               ++result;
+       }
+
        return result;
 }
 
@@ -298,6 +273,29 @@ static unsigned exam_subs_algebraic()
        return result;
 }
 
+/* Test suitable cases of the exponent power law: (e^t)^s=e^(ts). */
+static unsigned exam_exponent_power_law()
+{
+       unsigned result = 0;
+       symbol x("x");
+       realsymbol s("s");
+       possymbol t("t");
+
+       exmap pwr_exp =
+               { {pow(exp(x), 2), exp(2*x)},
+                 {pow(exp(s), t), exp(s*t)},
+                 {exp(x)*pow(exp(x),-1), 1} };
+
+       for (auto e : pwr_exp) {
+               if (! (e.first.is_equal(e.second)) ) {
+                       clog << "power of exponent  " << e.first << " produces error.\n";
+                       ++result;
+               }
+       }
+
+       return result;
+}
+
 unsigned exam_misc()
 {
        unsigned result = 0;
@@ -307,11 +305,11 @@ unsigned exam_misc()
        result += exam_expand_subs();  cout << '.' << flush;
        result += exam_expand_subs2();  cout << '.' << flush;
        result += exam_expand_power(); cout << '.' << flush;
-       result += exam_sqrfree(); cout << '.' << flush;
        result += exam_operator_semantics(); cout << '.' << flush;
        result += exam_subs(); cout << '.' << flush;
        result += exam_joris(); cout << '.' << flush;
        result += exam_subs_algebraic(); cout << '.' << flush;
+       result += exam_exponent_power_law(); cout << '.' << flush;
        
        return result;
 }
index c551c673b7e0b93da74e25f0e1fac2b78f947125..5b0675c94b08384aee8869054d3d8b2bfb52048a 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index ade01a68f34af1abe355454afa81b69e6dde9bb4..ded231f309cd08289b5fdab3a6e4e58ab4f400ca 100644 (file)
@@ -3,7 +3,7 @@
  *  Rational function normalization test suite. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -223,6 +223,113 @@ static unsigned exam_content()
        return result;
 }
 
+static unsigned exam_exponent_law()
+{
+       unsigned result = 0;
+       ex e, d;
+
+       // simple case
+       e = exp(2*x)-1;
+       e /= exp(x)-1;
+       d = exp(x)+1;
+       result += check_normal(e, d);
+
+       // More involved with powers of two exponents
+       e = exp(15*x)+exp(12*x)+2*exp(10*x)+2*exp(7*x);
+       e /= exp(5*x)+exp(2*x);
+       d = pow(exp(5*x), 2) +2*exp(5*x);
+       result += check_normal(e, d);
+
+       lst bases = {
+                5*exp(3*x)+7, // Powers of a single exponent
+                5*exp(3*x)+7*exp(2*x), // Two different factors of a single variable
+                5*exp(3*x)+7*exp(2*y) // Exponent with different variable
+       };
+
+       for (auto den : bases) {
+               e = pow(den, 3).expand();
+               e /= pow(den, 2).expand();
+               result += check_normal(e, den);
+       }
+
+       // Negative exponents
+       e = (exp(2*x)-exp(-2*x))/(exp(x)-exp(-x));
+       ex en = e.normal();
+       // Either exp(x) or exp(-x) can be viewed as a "symbol" during run-time
+       // thus two different forms of the result are possible
+       ex r1 = (exp(2*x)+1)/exp(x) ;
+       ex r2 = (exp(-2*x)+1)/exp(-x);
+
+       if (!en.is_equal(r1) && !en.is_equal(r2)) {
+               clog << "normal form of " << e << " erroneously returned "
+                    << en << " (should be " << r1 << " or " << r2 << ")" << endl;
+               result += 1;
+       }
+
+       return result;
+}
+
+static unsigned exam_power_law()
+{
+       unsigned result = 0;
+       ex e, d;
+
+       lst bases = {x, pow(x, numeric(1,3)), exp(x), sin(x)}; // We run all check for power base of different kinds
+
+       for ( auto b : bases ) {
+
+               // simple case
+               e = 4*b-9;
+               e /= 2*sqrt(b)-3;
+               d = 2*sqrt(b)+3;
+               result += check_normal(e, d);
+
+               // Fractional powers
+               e = 4*pow(b, numeric(2,3))-9;
+               e /= 2*pow(b, numeric(1,3))-3;
+               d = 2*pow(b, numeric(1,3))+3;
+               result += check_normal(e, d);
+
+               // Different powers with the same base
+               e = 4*b-9*sqrt(b);
+               e /= 2*sqrt(b)-3*pow(b, numeric(1,4));
+               d = 2*sqrt(b)+3*pow(b, numeric(1,4));
+               result += check_normal(e, d);
+
+               // Non-numeric powers
+               e = 4*pow(b, 2*y)-9;
+               e /= 2*pow(b, y)-3;
+               d = 2*pow(b, y)+3;
+               result += check_normal(e, d);
+
+               // Non-numeric fractional powers
+               e = 4*pow(b, y)-9;
+               e /= 2*pow(b, y/2)-3;
+               d = 2*pow(b, y/2)+3;
+               result += check_normal(e, d);
+
+               // Different non-numeric powers
+               e = 4*pow(b, 2*y)-9*pow(b, 2*z);
+               e /= 2*pow(b, y)-3*pow(b, z);
+               d = 2*pow(b, y)+3*pow(b, z);
+               result += check_normal(e, d);
+
+               // Different non-numeric fractional powers
+               e = 4*pow(b, y)-9*pow(b, z);
+               e /= 2*pow(b, y/2)-3*pow(b, z/2);
+               d = 2*pow(b, y/2)+3*pow(b, z/2);
+               result += check_normal(e, d);
+
+               // Negative powers
+               e = (b -pow(b,-1));
+               e /= (pow(b, numeric(1,2)) - pow(b, numeric(-1,2)));
+               d = (b+1)*pow(b, numeric(-1,2));
+               result += check_normal(e, d);
+       }
+
+       return result;
+}
+
 unsigned exam_normalization()
 {
        unsigned result = 0;
@@ -234,6 +341,8 @@ unsigned exam_normalization()
        result += exam_normal3(); cout << '.' << flush;
        result += exam_normal4(); cout << '.' << flush;
        result += exam_content(); cout << '.' << flush;
+       result += exam_exponent_law(); cout << '.' << flush;
+       result += exam_power_law(); cout << '.' << flush;
        
        return result;
 }
index ad7da61c1dd9a53321deb53b013e526cd72241c2..ebea234dd9620dece4fe96853fa3fa60ab620b46 100644 (file)
@@ -4,7 +4,7 @@
  *  tests on these numbers like is_integer() etc... */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index b5f1260816be3cd2c2249d919a56d56d8ebf5126..d8a6027db37a3525752d67d1056fa5935c6cfd2e 100644 (file)
@@ -6,7 +6,7 @@
  *  these oopses for good, so we run those stupid tests... */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -504,6 +504,17 @@ static unsigned exam_paranoia20()
        return result;
 }
 
+static unsigned exam_mul_info()
+{
+       symbol x("x"), y("y");
+       ex e = x*y;
+       if (!e.info(info_flags::indefinite)) {
+               clog << "eek, product of two symbols is NOT indefinite\n";
+               return 1;
+       }
+       return 0;
+}
+
 static unsigned is_polynomial_false_positive()
 {
        unsigned result = 0;
@@ -577,63 +588,75 @@ static unsigned exam_paranoia23()
        return result;
 }
 
-// Bug in sqrfree_yun (fixed 2016-02-02).
-static unsigned exam_paranoia24()
+// Bug in add ctor
+unsigned exam_paranoia24()
 {
-       unsigned result = 0;
-       symbol x("x");
-       ex e;
+       symbol a("a"), b("b"), c("c");
+       ex e = -a + 2*b + c;
 
-       e = (x-1)*(x+1) - x*x + 1;  // an unexpanded 0...
-       try {
-               ex f = sqrfree(e);
-               if (!f.is_zero()) {
-                       clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
-                       ++result;
-               }
-       } catch (const exception &err) {
-               clog << "sqrfree(" << e << ") throws " << err.what() << endl;
-               ++result;
+       if (e.diff(c).nops() > 1) {
+               clog << "diff(" << e << ",c) was not fully evaluated.\n";
+               return 1;
        }
+       return 0;
+}
 
-       e = pow(x-1,3) - expand(pow(x-1,3));  // ...still after differentiating...
-       try {
-               ex f = sqrfree(e);
-               if (!f.is_zero()) {
-                       clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
-                       ++result;
-               }
-       } catch (const exception &err) {
-               clog << "sqrfree(" << e << ") throws " << err.what() << endl;
-               ++result;
+// Bug in partial fraction expansion
+unsigned exam_paranoia25()
+{
+       symbol x("x");
+       ex ex1=pow(x,4)/(x-1)/4;
+       ex ex2=sqrfree_parfrac(ex1,x);
+       ex e = (ex1-ex2).normal();
+
+       if (! e.is_zero()) {
+               clog << "partial fraction expansion of " << ex1 << " produces error.\n";
+               return 1;
        }
+       return 0;
+}
 
-       e = pow(x-1,4) - expand(pow(x-1,4));  // ...and after differentiating twice.
-       try {
-               ex f = sqrfree(e);
-               if (!f.is_zero()) {
-                       clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
+// Bug in power expansion
+unsigned exam_paranoia26()
+{
+       unsigned result = 0;
+       symbol x("x"), y("y"), a("a");
+       possymbol s("s"), t("t");
+       exmap pwrs =
+         { {pow((x+1)*(y-2)*(s-3)*(t+4), a), pow((x+1)*(y-2)*(s-3), a)*pow(t+4, a)},
+           {pow(2*(x+1)*(y-2)*(s-3)*(t+4), a), pow(2,a)*pow((x+1)*(y-2)*(s-3), a)*pow(t+4, a)},
+           {pow(-(x+1)*(y-2)*(s-3)*(t+4), a), pow(-(x+1)*(y-2)*(s-3), a)*pow(t+4, a)},
+           {pow(-2*(x+1)*(y-2)*(s-3)*(t+4), a), pow(2,a)*pow(-(x+1)*(y-2)*(s-3), a)*pow(t+4, a)} };
+
+       for (auto e : pwrs) {
+               if (! (e.first.expand()).is_equal(e.second) ) {
+                       clog << "power expansion of " << e.first << " produces error.\n";
                        ++result;
                }
-       } catch (const exception &err) {
-               clog << "sqrfree(" << e << ") throws " << err.what() << endl;
-               ++result;
        }
 
        return result;
 }
 
-// Bug in add ctor
-unsigned exam_paranoia25()
+// Bug in collect()
+// cf. https://www.ginac.de/pipermail/ginac-list/2021-March/002337.html
+static unsigned exam_collect_multiply_referenced_lst()
 {
-       symbol a("a"), b("b"), c("c");
-       ex e = -a + 2*b + c;
-
-       if (e.diff(c).nops() > 1) {
-               clog << "diff(" << e << ",c) was not fully evaluated.\n";
-               return 1;
-       }
-       return 0;
+        unsigned result = 0;
+        symbol x("x"), y("y");
+        ex a = x + y;
+        ex l = lst{x, y};
+        ex l2 = l;  // make l a multiply referenced object
+
+        try {
+                ex b = collect(a, l);
+        } catch (const std::runtime_error & e) {
+                clog << "collect(" << ", " << l << ") threw a runtime_error("
+                     << e.what() << ")" << endl;
+                ++result;
+        }
+
+        return result;
 }
 
 unsigned exam_paranoia()
@@ -662,12 +685,15 @@ unsigned exam_paranoia()
        result += exam_paranoia18();  cout << '.' << flush;
        result += exam_paranoia19();  cout << '.' << flush;
        result += exam_paranoia20();  cout << '.' << flush;
+       result += exam_mul_info(); cout << '.' << flush;
        result += is_polynomial_false_positive(); cout << '.' << flush;
        result += exam_paranoia21();  cout << '.' << flush;
        result += exam_paranoia22();  cout << '.' << flush;
        result += exam_paranoia23();  cout << '.' << flush;
        result += exam_paranoia24();  cout << '.' << flush;
        result += exam_paranoia25();  cout << '.' << flush;
+       result += exam_paranoia26();  cout << '.' << flush;
+       result += exam_collect_multiply_referenced_lst();  cout << '.' << flush;
        
        return result;
 }
diff --git a/check/exam_parser.cpp b/check/exam_parser.cpp
new file mode 100644 (file)
index 0000000..2c65cd5
--- /dev/null
@@ -0,0 +1,218 @@
+/** @file parser_bugs.cpp
+ *
+ *  Check for some silly bugs in the parser. */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+using namespace std;
+
+// - a - b was misparsed as -a + b due to a bug in parser::parse_unary_expr()
+static int check1(ostream& err_str)
+{
+       const string srep("-a-b");
+       parser reader;
+       ex e = reader(srep);
+       ex a = reader.get_syms()["a"];
+       ex b = reader.get_syms()["b"];
+       ex g = - a - b;
+       ex d = (e - g).expand();
+       if (!d.is_zero()) {
+               err_str << "\"" << srep << "\" was misparsed as \""
+                       << e << "\"" << endl;
+               return 1;
+       }
+       return 0;
+}
+
+/// Parser was rejecting the valid expression '5 - (3*x)/10'.
+static int check2(ostream& err_str)
+{
+       const string srep("5-(3*x)/10");
+       parser reader;
+       ex e = reader(srep);
+       ex x = reader.get_syms()["x"];
+       ex g = 5 - (3*x)/10;
+       ex d = (e - g).expand();
+       if (!d.is_zero()) {
+               err_str << "\"" << srep << "\" was misparsed as \""
+                       << e << "\"" << endl;
+               return 1;
+       }
+       return 0;
+}
+
+/// parse_literal_expr forget to consume the token, so parser get
+/// very confused.
+static int check3(ostream& err_str)
+{
+       const string srep("5-(2*I)/3");
+       parser reader;
+       ex e = reader(srep);
+       ex g = numeric(5) - (numeric(2)*I)/3;
+       ex d = (e - g).expand();
+       if (!d.is_zero()) {
+               err_str << "\"" << srep << "\" was misparsed as \""
+                       << e << "\"" << endl;
+               return 1;
+       }
+       return 0;
+}
+
+/// parser happily accepted various junk like 'x^2()+1'
+static int check4(ostream& err_str)
+{
+       const string junk("x^2()+1");
+       parser reader;
+       ex e;
+       try {
+               e = reader(junk);
+               err_str << "parser accepts junk: \"" << junk << "\"" << endl;
+               return 1;
+       } catch (parse_error& err) {
+               // Ok, parser rejects the nonsense.
+               return 0;
+       }
+}
+
+// Check that two strings parse to equal expressions.
+static int check_eq(ostream &err_str, parser &reader, const char *expr1, const char *expr2)
+{
+       const string srep1(expr1);
+       const string srep2(expr2);
+       ex e1, e2;
+       try{ e1 = reader(srep1); } catch (const exception &e) {
+               err_str << "\"" << srep1 << "\" failed to parse: "
+                       << e.what() << endl;
+               return 1;
+       }
+       try{ e2 = reader(srep2); } catch (const exception &e) {
+               err_str << "\"" << srep2 << "\" failed to parse: "
+                       << e.what() << endl;
+               return 1;
+       }
+       if (!(e1-e2).expand().is_zero()) {
+               err_str << "\"" << srep1 << "\" was misparsed as \""
+                       << e1 << "\"" << endl;
+               return 1;
+       }
+       return 0;
+}
+
+// Tests for the interaction of the '^' operator with
+// the unary '+' and the unary '-' operators
+static int check5(ostream& err_str)
+{
+       parser reader;
+       return
+               +check_eq(err_str, reader, "3^2+1", "10")
+               +check_eq(err_str, reader, "3^+2-1", "8")
+               +check_eq(err_str, reader, "3^-2+1", "10/9")
+               +check_eq(err_str, reader, "3^-2/5", "1/45")
+               +check_eq(err_str, reader, "3^-2*5", "5/9")
+               +check_eq(err_str, reader, "3^-2-5", "-44/9")
+               +check_eq(err_str, reader, "3^(-2)+1", "10/9")
+               +check_eq(err_str, reader, "(3)^(-2)+1", "10/9")
+               +check_eq(err_str, reader, "+3^2+1", "10")
+               +check_eq(err_str, reader, "+3^+2+1", "10")
+               +check_eq(err_str, reader, "+3^-2+1", "10/9")
+               +check_eq(err_str, reader, "+3^-2/5", "1/45")
+               +check_eq(err_str, reader, "+3^-2*5", "5/9")
+               +check_eq(err_str, reader, "+3^-2-5", "-44/9")
+               +check_eq(err_str, reader, "-3^2+1", "-8")
+               +check_eq(err_str, reader, "-3^+2+1", "-8")
+               +check_eq(err_str, reader, "-3^-2+1", "8/9")
+               +check_eq(err_str, reader, "-3^-2/3", "-1/27")
+               +check_eq(err_str, reader, "1+2^3^4", "1+(2^81)")
+               +check_eq(err_str, reader, "2^3^4+1", "1+(2^81)")
+               +check_eq(err_str, reader, "2^+3^4+1", "1+(2^81)")
+               +check_eq(err_str, reader, "2^3^+4+1", "1+(2^81)");
+}
+
+// Tests for the interaction of the '*' operator with
+// the unary '+' and the unary '-' operators
+static int check6(ostream& err_str)
+{
+       parser reader;
+       return
+               +check_eq(err_str, reader, "3*+2-1", "5")
+               +check_eq(err_str, reader, "3*2+1", "7")
+               +check_eq(err_str, reader, "3*+2+1", "7")
+               +check_eq(err_str, reader, "3*-2+1", "-5")
+               +check_eq(err_str, reader, "3*-2/5", "-6/5")
+               +check_eq(err_str, reader, "3*-2*5", "-30")
+               +check_eq(err_str, reader, "3*-2-5", "-11")
+               +check_eq(err_str, reader, "3*(-2)+1", "-5")
+               +check_eq(err_str, reader, "(3)*(-2)+1", "-5")
+               +check_eq(err_str, reader, "+3*2+1", "7")
+               +check_eq(err_str, reader, "+3*+2+1", "7")
+               +check_eq(err_str, reader, "+3*-2+1", "-5")
+               +check_eq(err_str, reader, "+3*-2/5", "-6/5")
+               +check_eq(err_str, reader, "+3*-2*5", "-30")
+               +check_eq(err_str, reader, "+3*-2-5", "-11")
+               +check_eq(err_str, reader, "-3*2+1", "-5")
+               +check_eq(err_str, reader, "-3*+2+1", "-5")
+               +check_eq(err_str, reader, "-3*-2+1", "7")
+               +check_eq(err_str, reader, "-3*-2/3", "2")
+               +check_eq(err_str, reader, "1+2*3*4", "25")
+               +check_eq(err_str, reader, "2*3*4+1", "25")
+               +check_eq(err_str, reader, "2*+3*4+1", "25")
+               +check_eq(err_str, reader, "2*3*+4+1", "25");
+}
+
+// Tests for nested unary + and unary -
+static int check7(ostream& err_str)
+{
+       parser reader;
+       return
+               +check_eq(err_str, reader, "+1", "1")
+               +check_eq(err_str, reader, "++1", "1")
+               +check_eq(err_str, reader, "+-+1", "-1")
+               +check_eq(err_str, reader, "+-+-1", "1")
+               +check_eq(err_str, reader, "+-+-+1", "1")
+               +check_eq(err_str, reader, "100++--+1+10", "111");
+}
+
+int main(int argc, char** argv)
+{
+       cout << "examining old parser bugs" << flush;
+       ostringstream err_str;
+       int errors = 0;
+       errors += check1(err_str);  cout << '.' << flush;
+       errors += check2(err_str);  cout << '.' << flush;
+       errors += check3(err_str);  cout << '.' << flush;
+       errors += check4(err_str);  cout << '.' << flush;
+       errors += check5(err_str);  cout << '.' << flush;
+       errors += check6(err_str);  cout << '.' << flush;
+       errors += check7(err_str);  cout << '.' << flush;
+       if (errors) {
+               cout << "Yes, unfortunately:" << endl;
+               cout << err_str.str();
+       } else {
+               cout << "Not found. ";
+       }
+       return errors;
+}
diff --git a/check/exam_pgcd.cpp b/check/exam_pgcd.cpp
new file mode 100644 (file)
index 0000000..0d61c6e
--- /dev/null
@@ -0,0 +1,68 @@
+/** @file exam_pgcd.cpp
+ *
+ * Exam GCD over prime fields computations.
+ */
+#include <string>
+#include <iostream>
+#include <utility>
+#include "ginac.h"
+using namespace std;
+using namespace GiNaC;
+
+// Check for an infite loop in PGCD, fixed 2010-02-23.
+static unsigned pgcd_relatively_prime_bug()
+{
+       const symbol q("q");
+       parser reader;
+       reader.get_syms().insert(make_pair(string("q"), q));
+
+       ex t = reader("-E20^16*E4^8*E5^8*E1^16*q^4"
+                     "-(E10^24-E20^8*E5^16)*E4^16*E1^8"
+                     "+E2^24*E20^16*E5^8*q^4");
+       ex g = gcd(t.expand(), t.diff(q).expand()) - 1;
+       if (!g.is_zero()) {
+               clog << " oops!" << endl <<
+                       "** Error: should be 0, got " << g << endl;
+               return 1;
+       }
+       return 0;
+}
+
+// Check for an infinite loop in PGCD, fixed 2010-03-18.
+static unsigned pgcd_infinite_loop()
+{
+       parser the_parser;
+       ex e = the_parser(string(R"ex(792*z^8*w^4*x^3*y^4*u^7
++ 24*z^4*w^4*x^2*y^3*u^4 + 264*z^8*w^3*x^2*y^7*u^5 + 198*z^4*w^5*x^5*y*u^6
++ 110*z^2*w^3*x^5*y^4*u^6 - 120*z^8*w*x^4*u^6 - 480*z^5*w*x^4*y^6*u^8
+- 720*z^7*x^3*y^3*u^7 + 165*z^4*w^2*x^4*y*u^5 + 450*z^8*w^6*x^2*y*u^8
++ 40*z^2*w^3*x^3*y^3*u^6 - 288*z^7*w^2*x^3*y^6*u^6 + 250*z^6*w^4*x^2*y^4*u^8
++ 576*z^7*w^7*x^2*y^4*u^8 - 80*z^6*w^2*x^5*y^3*u^7 - 144*z^8*w^4*x^5*u^7
++ 120*z^4*w*x^2*y^6*u^6 + 320*z^5*w^5*x^2*y^7*u^8 + 192*z^7*w^6*x*y^7*u^6
+- 12*z^4*w^3*x^3*y^5*u^6 - 36*z^4*w^4*x^4*y^2*u^8 + 72*z^4*w^5*x^3*u^6
+- 20*z^2*w^2*x^4*y^5*u^8 + 660*z^8*w*x^2*y^4*u^6 + 66*z^4*w^4*x^4*y^4*u^4
++ 440*z^6*w^2*x^3*y^7*u^7 - 30*z^4*w*x^3*y^2*u^7 - 48*z^8*w^3*x^4*y^3*u^5
++ 72*z^6*w^2*x*y^6*u^4 - 864*z^7*w^3*x^4*y^3*u^8 + 480*z^7*w^4*x*y^4*u^7
++ 60*z^4*w^2*x^2*u^5 + 375*z^8*w^3*x*y*u^7 + 150*z^8*w^5*x*y^4*u^6
++ 180*z^6*x*y^3*u^5 + 216*z^6*w^3*x^2*y^3*u^6)ex"));
+       const symbol x = ex_to<symbol>(the_parser.get_syms()["x"]);
+       ex g = gcd(e, e.diff(x));
+       ex should_be = the_parser(string("u^4*z^2"));
+       if (!(g-should_be).expand().is_zero()) {
+               clog << "GCD was miscomputed. " << endl;
+               return 1;
+       }
+       return 0;
+}
+
+int main()
+{
+       unsigned result = 0;
+
+       cout << "Examining pgcd() bugs (infinite loop, miscalculation)" << flush;
+
+       result += pgcd_relatively_prime_bug();  cout << '.' << flush;
+       result += pgcd_infinite_loop();  cout << '.' << flush;
+
+       return result;
+}
index aac25c85dca9e5ed9869ee52887f20df7387f75a..ba2570da9cdf7ef7497decde14302051bf36c840 100644 (file)
@@ -4,7 +4,7 @@
  *  rational function normalization in normalization.cpp. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index fb7328f55dfdc09e39764b25976391ece772cdcc..b6b105521e3aae577f3e0f131d5dfa2ae946cc3f 100644 (file)
@@ -4,7 +4,7 @@
  *  this code, it is a sanity check rather deeply rooted in GiNaC's classes. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e59026c494384a0124d203962c19d1310c77c308..c2669c422df43878a011a41bcb25c4bb15dc2580 100644 (file)
@@ -3,7 +3,7 @@
  *  Series expansion test (Laurent and Taylor series). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -390,6 +390,24 @@ static unsigned exam_series14()
        return result;
 }
 
+// Test expansion of powers of polynomials.
+static unsigned exam_series15()
+{
+       unsigned result = 0;
+
+       ex e = pow(x + pow(x,2), 2);
+
+       result += check_series(e, 0, Order(1), 0);
+       result += check_series(e, 0, Order(x), 1);
+       result += check_series(e, 0, Order(pow(x,2)), 2);
+       result += check_series(e, 0, pow(x,2) + Order(pow(x,3)), 3);
+       result += check_series(e, 0, pow(x,2) + 2*pow(x,3) + Order(pow(x,4)), 4);
+       result += check_series(e, 0, pow(x,2) + 2*pow(x,3) + pow(x,4), 5);
+       result += check_series(e, 0, pow(x,2) + 2*pow(x,3) + pow(x,4), 6);
+
+       return result;
+}
+
 unsigned exam_pseries()
 {
        unsigned result = 0;
@@ -410,6 +428,7 @@ unsigned exam_pseries()
        result += exam_series12();  cout << '.' << flush;
        result += exam_series13();  cout << '.' << flush;
        result += exam_series14();  cout << '.' << flush;
+       result += exam_series15();  cout << '.' << flush;
        
        return result;
 }
index dc24f0a2dcd258b5d82299881b33bb69a08830e2..7c0b441537e6aa58d91b6b2baa3d6148970ab460 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/check/exam_relational.cpp b/check/exam_relational.cpp
new file mode 100644 (file)
index 0000000..ec9a2d7
--- /dev/null
@@ -0,0 +1,151 @@
+/** @file exam_relational.cpp
+ *
+ *  Small test for the relational objects and their conversion to bool. */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+using namespace std;
+
+// Elementary relations should fall back to numeric comparisons.
+static unsigned exam_relational_elementary()
+{
+       unsigned result = 0;
+       ex one = 1, two = 2;
+
+       if (one == two) {
+               clog << "'" << one << " == " << two << "' was converted to true." << endl;
+               result += 1;
+       }
+       if (!(one != two)) {
+               clog << "'" << one << " != " << two << "' was not converted to true." << endl;
+               result += 1;
+       }
+       if (!(one < two)) {
+               clog << "'" << one << " < " << two << "' was not converted to true." << endl;
+               result += 1;
+       }
+       if (!(one <= two)) {
+               clog << "'" << one << " <= " << two << "' was not converted to true." << endl;
+               result += 1;
+       }
+       if (one > two) {
+               clog << "'" << one << " > " << two << "' was converted to true." << endl;
+               result += 1;
+       }
+       if (one >= two) {
+               clog << "'" << one << " >= " << two << "' was converted to true." << endl;
+               result += 1;
+       }
+
+       return result;
+}
+
+// These should fall back to looking up info flags.
+static unsigned exam_relational_possymbol()
+{
+       unsigned result = 0;
+       possymbol p("p");
+
+       if (p == 0) {
+               clog << "for positive p, 'p == 0' was converted to true." << endl;
+               result += 1;
+       }
+       if (!(p != 0)) {
+               clog << "for positive p, 'p != 0' was not converted to true." << endl;
+               result += 1;
+       }
+       if (p < 0) {
+               clog << "for positive p, 'p < 0' was converted to true." << endl;
+               result += 1;
+       }
+       if (p <= 0) {
+               clog << "for positive p, 'p <= 0' was converted to true." << endl;
+               result += 1;
+       }
+       if (!(p > 0)) {
+               clog << "for positive p, 'p > 0' was not converted to true." << endl;
+               result += 1;
+       }
+       if (!(p >= 0)) {
+               clog << "for positive p, 'p >= 0' was not converted to true." << endl;
+               result += 1;
+       }
+
+       return result;
+}
+
+// Very simple arithmetic should be supported, too.
+static unsigned exam_relational_arith()
+{
+       unsigned result = 0;
+       possymbol p("p");
+
+       if (!(p + 2 > p + 1)) {
+               clog << "for positive p, 'p + 2 > p + 1' was not converted to true." << endl;
+               result += 1;
+       }
+       if (!(p > -p)) {
+               clog << "for positive p, 'p > -p' was not converted to true." << endl;
+               result += 1;
+       }
+       if (!(2*p > p)) {
+               clog << "for positive p, '2*p > p' was not converted to true." << endl;
+               result += 1;
+       }
+
+       return result;
+}
+
+// Comparisons should maintain ordering invariants
+static unsigned exam_relational_order()
+{
+       unsigned result = 0;
+       numeric i = 1ll<<32, j = i+1;
+       symbol a;
+       relational x = i==a, y = j==a;
+       if (x.compare(y) != -y.compare(x)) {
+               clog << "comparison should be antisymmetric." << endl;
+               result += 1;
+       }
+
+       return result;
+}
+
+unsigned exam_relational()
+{
+       unsigned result = 0;
+
+       cout << "examining relational objects" << flush;
+
+       result += exam_relational_elementary(); cout << '.' << flush;
+       result += exam_relational_possymbol(); cout << '.' << flush;
+       result += exam_relational_arith(); cout << '.' << flush;
+       result += exam_relational_order(); cout << '.' << flush;
+
+       return result;
+}
+
+int main(int argc, char** argv)
+{
+       return exam_relational();
+}
diff --git a/check/exam_sqrfree.cpp b/check/exam_sqrfree.cpp
new file mode 100644 (file)
index 0000000..014d703
--- /dev/null
@@ -0,0 +1,243 @@
+/** @file exam_sqrfree.cpp
+ *
+ */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+using namespace std;
+
+static unsigned exam_sqrfree1()
+{
+       unsigned result = 0;
+       symbol x("x");
+       ex e1, e2;
+
+       e1 = (1+x)*pow((2+x),2)*pow((3+x),3)*pow((4+x),4);
+       e2 = sqrfree(expand(e1), lst{x});
+       if (e1 != e2) {
+               clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+
+       return result;
+}
+
+static unsigned exam_sqrfree2()
+{
+       unsigned result = 0;
+       symbol x("x"), y("y");
+       ex e1, e2;
+
+       e1 = (x+y)*pow((x+2*y),2)*pow((x+3*y),3)*pow((x+4*y),4);
+       e2 = sqrfree(expand(e1));
+       if (e1 != e2) {
+               clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+       e2 = sqrfree(expand(e1), lst{x});
+       if (e1 != e2) {
+               clog << "sqrfree(expand(" << e1 << "),[x]) erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+       e2 = sqrfree(expand(e1), lst{y});
+       if (e1 != e2) {
+               clog << "sqrfree(expand(" << e1 << "),[y]) erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+       e2 = sqrfree(expand(e1), lst{x,y});
+       if (e1 != e2) {
+               clog << "sqrfree(expand(" << e1 << "),[x,y]) erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+
+       return result;
+}
+
+static unsigned exam_sqrfree3()
+{
+       unsigned result = 0;
+       symbol x("x"), y("y"), z("z");
+       ex e1, e2;
+
+       e1 = (x+y)*pow(x, 2)*(-z-1);
+       e2 = sqrfree(expand(e1));
+       if (!expand(e1 - e2).is_zero()) {
+               clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+
+       e1 = (x+y)*pow(x, 3)*(-z-1);
+       e2 = sqrfree(expand(e1));
+       if (!expand(e1 - e2).is_zero()) {
+               clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+
+       return result;
+}
+
+// Bug in sqrfree_yun (fixed 2016-02-02).
+static unsigned exam_hidden_zero1()
+{
+       unsigned result = 0;
+       symbol x("x");
+       ex e;
+
+       e = (x-1)*(x+1) - x*x + 1;  // an unexpanded 0...
+       try {
+                ex f = sqrfree(e);
+                if (!f.is_zero()) {
+                        clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
+                        ++result;
+                }
+        } catch (const exception &err) {
+                clog << "sqrfree(" << e << ") throws " << err.what() << endl;
+                ++result;
+        }
+
+       e = pow(x-1,3) - expand(pow(x-1,3));  // ...still after differentiating...
+       try {
+                ex f = sqrfree(e);
+                if (!f.is_zero()) {
+                        clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
+                        ++result;
+                }
+        } catch (const exception &err) {
+                clog << "sqrfree(" << e << ") throws " << err.what() << endl;
+                ++result;
+        }
+
+       e = pow(x-1,4) - expand(pow(x-1,4));  // ...and after differentiating twice.
+       try {
+                ex f = sqrfree(e);
+                if (!f.is_zero()) {
+                        clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
+                        ++result;
+                }
+        } catch (const exception &err) {
+                clog << "sqrfree(" << e << ") throws " << err.what() << endl;
+                ++result;
+        }
+
+       return result;
+}
+
+static unsigned exam_hidden_zero2()
+{
+       unsigned result = 0;
+       symbol x("x"), y("y");
+       ex e1, e2;
+
+       e1 = (1 + 3*x + 3*pow(x,2) + pow(x,3) - pow(1+x,3)) * y;
+       e2 = sqrfree(e1);
+       if (!e2.is_zero()) {
+               clog << "sqrfree(" << e1 << ") erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+
+       e1 = (pow(x,2)-2*x*y+pow(y,2)-pow(x-y,2)) * x;
+       e2 = sqrfree(e1);
+       if (!e2.is_zero()) {
+               clog << "sqrfree(" << e1 << ") erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+
+       e1 = (pow(x,2)-2*x*y+pow(y,2)-pow(x-y,2)) * (x+y);
+       e2 = sqrfree(e1);
+       if (!e2.is_zero()) {
+               clog << "sqrfree(" << e1 << ") erroneously returned "
+                    << e2 << endl;
+               ++result;
+       }
+
+       return result;
+}
+
+unsigned exam_sqrfree()
+{
+       unsigned result = 0;
+
+       cout << "examining square-free factorization" << flush;
+
+       result += exam_sqrfree1();  cout << '.' << flush;
+       result += exam_sqrfree2();  cout << '.' << flush;
+       result += exam_sqrfree3();  cout << '.' << flush;
+       result += exam_hidden_zero1();  cout << '.' << flush;
+       result += exam_hidden_zero2();  cout << '.' << flush;
+
+       return result;
+}
+
+unsigned exam_sqrfree_parfrac()
+{
+       symbol x("x");
+       // (expression, number of terms after partial fraction decomposition)
+       vector<pair<ex, unsigned>> exams = {
+               {ex("(x - 1) / (x^2*(x^2 + 2))", lst{x}), 3},
+               {ex("(1 - x^10) / x", lst{x}), 2},
+               {ex("(2*x^3 + x + 3) / ((x^2 + 1)^2)", lst{x}), 2},
+               {ex("1 / (x * (x+1)^2 * (x+2)^3)", lst{x}), 6},
+               {ex("(x*x + 3*x - 1) / (x^2*(x^2 + 2)^3)", lst{x}), 5},
+               {ex("(1 - x^10) / (x + 2)", lst{x}), 11},
+               {ex("(1 - x + 3*x^2) / (x^3 * (2+x)^2)", lst{x}), 5},
+               {ex("(1 - x) / (x^4 * (x - 2)^3)", lst{x}), 6},
+               {ex("(1 - 2*x + x^9) / (x^5 * (1 - x + x^2)^6)", lst{x}), 11}
+       };
+       unsigned result = 0;
+
+       cout << "\n"
+            << "examining square-free partial fraction decomposition" << flush;
+       for (auto e: exams) {
+               ex e1 = e.first;
+               ex e2 = sqrfree_parfrac(e1, x);
+               if (e2.nops() != e.second ||
+                   !is_a<add>(e2) ||
+                   !normal(e1-e2).is_zero()) {
+                       clog << "sqrfree_parfrac(" << e1 << ", " << x << ") erroneously returned "
+                            << e2 << endl;
+                       ++result;
+               }
+               cout << '.' << flush;
+       }
+
+       return result;
+}
+
+int main(int argc, char** argv)
+{
+       unsigned result = 0;
+
+       result += exam_sqrfree();
+       result += exam_sqrfree_parfrac();
+
+       return result;
+}
index 5aa163749fe45fd5df950d2d698e65177d530ac3..b9a403a9f7d62dc5054476fbef2a2c9f84012207 100644 (file)
@@ -3,7 +3,7 @@
  *  Small test for the structure<> template. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/check/factor_univariate_bug.cpp b/check/factor_univariate_bug.cpp
deleted file mode 100644 (file)
index 80a7ce4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @file factor_upoly_q_bug.cpp Check for a bug in factor_univariate().
- *
- * factor_univariate() didn't check if the argument is an integer polynomial,
- * the result was a segfault.
- */
-#include "ginac.h"
-#include <iostream>
-using namespace GiNaC;
-using namespace std;
-
-int main(int argc, char** argv)
-{
-       cout << "checking if factor() handles rational polynomials. ";
-       parser p;
-       ex e = p("174247781*x^2-1989199947807987/200000000000000*x");
-       ex ef = factor(e);
-       ex diff = (e - ef).expand();
-       cout << "yes" << endl;
-       return 0;
-}
index 981e193c12898c8dd27c101c9206e724ec31e230..84b7fc0ec6d69c15024331772a013a8a34d2cacb 100644 (file)
@@ -4,7 +4,7 @@
  *  input in the consistency checks. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/check/mul_eval_memleak.cpp b/check/mul_eval_memleak.cpp
deleted file mode 100644 (file)
index 0d2b1d6..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/** @file mul_eval_memleak.cpp
- *
- *  mul_eval_memleak.cpp Test for memory leak in {mul,power}::eval
- *
- *  The bug was introduced by
- *
- *  commit f418c6ee4d558c852e1fb95533af07a3ae43f409
- *  Author: Alexei Sheplyakov <varg@theor.jinr.ru>
- *  Date:   Wed Jul 11 14:34:42 2007 +0400
- *  (it was commited into the official branch as
- *  commit a602d34c225dceb3e53742a7b3e19a4b5e280485
- *  Author: Jens Vollinga <vollinga@thep.physik.uni-mainz.de>
- *  Date:   Wed Jul 11 21:07:40 2007 +0000)
- */
-
-/*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <ginac/ginac.h>
-using namespace GiNaC;
-
-#include <iostream>
-#include <stdexcept>
-#include <string>
-using namespace std;
-
-const unsigned check_mul_eval_memleak(const unsigned N)
-{
-       // Expanding this expression into a Laurent series triggers the bug.
-       static const string e_str("\
-1/605927415293858601*tgamma(3-eps)^(-1)*tgamma(2-eps)*(5013234896802\
-*(-1+2*eps)*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log(920*scale\
-^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F)+(846400+2539001*eps\
-)*(2539001*(-1+2*eps)*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log\
-(920*scale^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F)+286523497\
-2800*(-1+eps)^(-1)*eps^(-2)*(920*scale^(-1))^(-2*eps)*(1301*scale^(-\
-1))^(-2*eps)*tgamma(1+eps)^2)+6061411748045832000*(-1+eps)^(-1)*eps^\
-(-2)*(920*scale^(-1))^(-2*eps)*(1301*scale^(-1))^(-2*eps)*tgamma(1+e\
-ps)^2+716056132401*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log(92\
-0*scale^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F))+71656139360\
-0/716056132401*tgamma(1-eps)*tgamma(2*eps)^(-1)*tgamma(eps)^2*tgamma\
-(3-eps)^(-1)*(920*scale^(-1))^(-4*eps)*tgamma(-1+2*eps)-2/6059274152\
-93858601*tgamma(3-eps)^(-1)*(2149010446400*(-1+2*eps)*((-2539001/2)*\
-eps^(-2)+(-7617003/2+1692800*log(920*scale^(-1))+3385202*log(1301*sc\
-ale^(-1)))*eps^(-1)+F)+2425134880977920000*(-1+eps)^(-1)*eps^(-2)*(9\
-20*scale^(-1))^(-2*eps)*(1301*scale^(-1))^(-2*eps)*tgamma(1+eps)^2-7\
-16056132401*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log(920*scale\
-^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F)+1692601*(-1+2*eps)*\
-(2539001*(-1+2*eps)*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log(9\
-20*scale^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F)+28652349728\
-00*(-1+eps)^(-1)*eps^(-2)*(920*scale^(-1))^(-2*eps)*(1301*scale^(-1)\
-)^(-2*eps)*tgamma(1+eps)^2))*tgamma(2-eps)+(1/716056132401*I)*tgamma\
-(-1+eps)*mb^2*(mb*scale^(-1))^(-2*eps)*((716392960000*I)*mb^(-2)*(92\
-0*scale^(-1))^(-2*eps)*tgamma(-2+eps)-(2864898145201*I)*mb^(-2)*(130\
-1*scale^(-1))^(-2*eps)*tgamma(-2+eps)-(716224526400*I)*tgamma(-1+eps\
-)*mb^(-2)*(920*scale^(-1))^(-2*eps))-3385202/605927415293858601*tgam\
-ma(3-eps)^(-1)*tgamma(2-eps)*(2539001*(-1+2*eps)*((-2539001/2)*eps^(\
--2)+(-7617003/2+1692800*log(920*scale^(-1))+3385202*log(1301*scale^(\
--1)))*eps^(-1)+F)+2865234972800*(-1+eps)^(-1)*eps^(-2)*(920*scale^(-\
-1))^(-2*eps)*(1301*scale^(-1))^(-2*eps)*tgamma(1+eps)^2+846201*((-25\
-39001/2)*eps^(-2)+(-7617003/2+1692800*log(920*scale^(-1))+3385202*lo\
-g(1301*scale^(-1)))*eps^(-1)+F))\
-");
-       const symbol eps("eps"), scale("scale"), mb("mb"), F("F");
-       const lst syms(eps, scale, mb, F);
-       const ex e0(e_str, syms);
-
-       unsigned i = 0;
-       unsigned n_failures = 0;
-
-       ex e;
-       try {
-               for (; i < N; i++)
-                       e = e0.series(eps, 1).subs(Euler==0).expand();
-       } catch (std::bad_alloc) {
-               return i;
-       }
-       return 0;
-}
-                       
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-static void set_VM_limit(const unsigned long MB) {
-       const unsigned mem_lim_kb = MB*1024*1024;
-       struct rlimit lim;
-       lim.rlim_cur = mem_lim_kb;
-       lim.rlim_max = mem_lim_kb;
-       setrlimit(RLIMIT_AS, &lim);
-}
-
-int main(int argc, char** argv) {
-       static const unsigned max_mem = 32; // megabytes
-       // otherwise one need wait for a long[er] time.
-       set_VM_limit(max_mem); 
-       static const unsigned n_of_tests = 10000;
-       const unsigned n_loops = check_mul_eval_memleak(n_of_tests);
-       if (n_loops) {
-               cerr << "memory exhausted after " << n_loops << " loops" << endl;
-               return 1;
-       }
-       return 0;
-}
diff --git a/check/numeric_archive.cpp b/check/numeric_archive.cpp
deleted file mode 100644 (file)
index a7d410c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/** @file numeric_archive.cpp
- *
- *  Check for a bug in numeric::archive
- *
- *  numeric::archive used to fail if the real part of a complex number
- *  is a rational number and the imaginary part is a floating point one. */
-
-/*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "ginac.h"
-using namespace GiNaC;
-
-#include <algorithm>
-#include <cln/cln.h>
-#include <iostream>
-#include <iterator>
-#include <sstream>
-#include <stdexcept>
-#include <vector>
-using namespace cln;
-
-struct archive_unarchive_check
-{
-       cl_N operator()(const cl_N& n) const
-       {
-               ex e = numeric(n);
-               archive ar;
-               ar.archive_ex(e, "test");
-               lst l;
-               ex check = ar.unarchive_ex(l, "test");
-               if (!check.is_equal(e)) {
-                       std::ostringstream s;
-                       s << __FILE__ << ':' << __LINE__ << ": expected: " << e << ", got " << check;
-                       throw std::logic_error(s.str());
-               }
-               return n;
-       }
-};
-
-int main(int argc, char** argv)
-{
-       const cl_I one(1);
-       std::cout << "checking if numeric::archive handles complex numbers properly" << std::endl;
-       const cl_R three_fp = cl_float(3.0, default_float_format);
-       std::vector<cl_N> numbers;
-       numbers.push_back(complex(one, three_fp));
-       numbers.push_back(complex(three_fp, one));
-       numbers.push_back(complex(three_fp, three_fp));
-       numbers.push_back(complex(one, one));
-       std::for_each(numbers.begin(), numbers.end(), archive_unarchive_check());
-       return 0;
-}
diff --git a/check/parser_bugs.cpp b/check/parser_bugs.cpp
deleted file mode 100644 (file)
index 3821049..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/** @file parser_bugs.cpp
- *
- *  Check for some silly bugs in the parser. */
-
-/*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "ginac.h"
-using namespace GiNaC;
-
-#include <iostream>
-#include <sstream>
-#include <stdexcept>
-#include <string>
-
-// - a - b was misparsed as -a + b due to a bug in parser::parse_unary_expr()
-static int check1(std::ostream& err_str)
-{
-       const std::string srep("-a-b");
-       parser reader;
-       ex e = reader(srep);
-       ex a = reader.get_syms()["a"];
-       ex b = reader.get_syms()["b"];
-       ex g = - a - b;
-       ex d = (e - g).expand();
-       if (!d.is_zero()) {
-               err_str << "\"" << srep << "\" was misparsed as \""
-                       << e << "\"" << std::endl;
-               return 1;
-       }
-       return 0;
-}
-
-/// Parser was rejecting the valid expression '5 - (3*x)/10'.
-static int check2(std::ostream& err_str)
-{
-       const std::string srep("5-(3*x)/10");
-       parser reader;
-       ex e = reader(srep);
-       ex x = reader.get_syms()["x"];
-       ex g = 5 - (3*x)/10;
-       ex d = (e - g).expand();
-       if (!d.is_zero()) {
-               err_str << "\"" << srep << "\" was misparsed as \""
-                       << e << "\"" << std::endl;
-               return 1;
-       }
-       return 0;
-}
-
-/// parse_literal_expr forget to consume the token, so parser get
-/// very confused.
-static int check3(std::ostream& err_str)
-{
-       const std::string srep("5-(2*I)/3");
-       parser reader;
-       ex e = reader(srep);
-       ex g = numeric(5) - (numeric(2)*I)/3;
-       ex d = (e - g).expand();
-       if (!d.is_zero()) {
-               err_str << "\"" << srep << "\" was misparsed as \""
-                       << e << "\"" << std::endl;
-               return 1;
-       }
-       return 0;
-}
-
-/// parser happily accepted various junk like 'x^2()+1'
-static int check4(std::ostream& err_str)
-{
-       const std::string junk("x^2()+1");
-       parser reader;
-       ex e;
-       try {
-               e = reader(junk);
-               err_str << "parser accepts junk: \"" << junk << "\"" << std::endl;
-               return 1;
-       } catch (parse_error& err) {
-               // Ok, parser rejects the nonsense.
-               return 0;
-       }
-}
-
-int main(int argc, char** argv)
-{
-       std::cout << "checking for parser bugs. " << std::flush;
-       std::ostringstream err_str;
-       int errors = 0;
-       errors += check1(err_str);
-       errors += check2(err_str);
-       errors += check3(err_str);
-       errors += check4(err_str);
-       if (errors) {
-               std::cout << "Yes, unfortunately:" << std::endl;
-               std::cout << err_str.str();
-       } else {
-               std::cout << "Not found. ";
-       }
-       return errors;
-}
diff --git a/check/parser_memleak.cpp b/check/parser_memleak.cpp
deleted file mode 100644 (file)
index ffe095d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/** @file parser_memleak.cpp
- *
- *  This small program exhibits the memory leak in the ginac_yylex().
- *  Run it as
- *
- *  valgrind --leak-check=yes  ./parser_memleak
- *
- *  or simply
- *
- *  ulimit -v `expr 64 \* 1024` ./parser_memleak
- */
-
-/*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <ginac/ginac.h>
-using namespace GiNaC;
-
-#include <iostream>
-#include <stdexcept>
-using namespace std;
-
-int main(int argc, char** argv) {
-       const symbol x("x"), y("y");
-       const lst syms(x, y);
-       // parser-generated symbol => memory leak.
-       static const char* str[] = { "x^2+2*x*y + cos(x)", "Li2(x/y) + log(y/x)" };
-       
-       // depends on the amount of the available VM, compiler options, etc.
-       const unsigned N_max = 500000;
-       unsigned N=0;
-       ex e;
-       try {
-               for (; N < N_max; N++) {
-                       e = ex(str[N & 1], syms);
-               }
-       } catch (std::bad_alloc) {
-               cerr << "N = " << N << endl;
-               return 1;
-       }
-       return 0;
-}
diff --git a/check/pgcd_infinite_loop.cpp b/check/pgcd_infinite_loop.cpp
deleted file mode 100644 (file)
index 0ad5a70..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#include <iostream>
-#include <string>
-#include "ginac.h"
-using namespace GiNaC;
-using namespace std;
-
-static const string srep("\
-792*z^8*w^4*x^3*y^4*u^7 + 24*z^4*w^4*x^2*y^3*u^4       \
-+ 264*z^8*w^3*x^2*y^7*u^5 + 198*z^4*w^5*x^5*y*u^6      \
-+ 110*z^2*w^3*x^5*y^4*u^6 - 120*z^8*w*x^4*u^6          \
-- 480*z^5*w*x^4*y^6*u^8 - 720*z^7*x^3*y^3*u^7          \
-+ 165*z^4*w^2*x^4*y*u^5 + 450*z^8*w^6*x^2*y*u^8                \
-+ 40*z^2*w^3*x^3*y^3*u^6 - 288*z^7*w^2*x^3*y^6*u^6     \
-+ 250*z^6*w^4*x^2*y^4*u^8 + 576*z^7*w^7*x^2*y^4*u^8    \
-- 80*z^6*w^2*x^5*y^3*u^7 - 144*z^8*w^4*x^5*u^7         \
-+ 120*z^4*w*x^2*y^6*u^6 + 320*z^5*w^5*x^2*y^7*u^8      \
-+ 192*z^7*w^6*x*y^7*u^6 - 12*z^4*w^3*x^3*y^5*u^6       \
-- 36*z^4*w^4*x^4*y^2*u^8 + 72*z^4*w^5*x^3*u^6          \
-- 20*z^2*w^2*x^4*y^5*u^8 + 660*z^8*w*x^2*y^4*u^6       \
-+ 66*z^4*w^4*x^4*y^4*u^4 + 440*z^6*w^2*x^3*y^7*u^7     \
-- 30*z^4*w*x^3*y^2*u^7 - 48*z^8*w^3*x^4*y^3*u^5                \
-+ 72*z^6*w^2*x*y^6*u^4 - 864*z^7*w^3*x^4*y^3*u^8       \
-+ 480*z^7*w^4*x*y^4*u^7 + 60*z^4*w^2*x^2*u^5           \
-+ 375*z^8*w^3*x*y*u^7 + 150*z^8*w^5*x*y^4*u^6          \
-+ 180*z^6*x*y^3*u^5 + 216*z^6*w^3*x^2*y^3*u^6");
-
-int main(int argc, char** argv)
-{
-       cout << "Checking for more pgcd() bugs (infinite loop, miscalculation) ... " << flush;
-       parser the_parser;
-       ex e = the_parser(srep);
-       const symbol x = ex_to<symbol>(the_parser.get_syms()["x"]);
-       ex g = gcd(e, e.diff(x));
-       ex should_be = the_parser(string("u^4*z^2"));
-       if (!(g-should_be).expand().is_zero()) {
-               cout << "GCD was miscomputed. " << flush;
-               return 1;
-       }
-       cout << "not found. " << flush;
-       return 0;
-}
diff --git a/check/pgcd_relatively_prime_bug.cpp b/check/pgcd_relatively_prime_bug.cpp
deleted file mode 100644 (file)
index 1d4c287..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/** @file pgcd_relatively_prime_bug.cpp
- *
- * A program exposing historical bug in the pgcd() function. 
- */
-#include <string>
-#include <iostream>
-#include <utility>
-#include "ginac.h"
-using namespace std;
-using namespace GiNaC;
-
-int main(int argc, char** argv)
-{
-       cout << "Checking for pgcd() bug regarding relatively prime polynomials: " << flush;
-       const symbol q("q");
-       parser reader;
-       reader.get_syms().insert(make_pair(string("q"), q));
-
-       ex t = reader("-E20^16*E4^8*E5^8*E1^16*q^4"
-                     "-(E10^24-E20^8*E5^16)*E4^16*E1^8"
-                     "+E2^24*E20^16*E5^8*q^4");
-       ex g = gcd(t.expand(), t.diff(q).expand()) - 1;
-       if (!g.is_zero()) {
-               cout << " oops!" << endl <<
-                       "** Error: should be 0, got " << g << endl << flush;
-               throw std::logic_error("gcd was miscalculated");
-       }
-       cout << "not found" << endl << flush;
-       return 0;
-}
-
index ab34ba0044040f064a3f1093b8726d14be3c2387..9819449474a839bf6fec4d156c1ccd818bd4af55 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 4a306350f6e0b7de889dcb74275ea9f58fd76b11..e3c7315ad30c9edd704375aa9358d46a1bc675f7 100644 (file)
@@ -3,7 +3,7 @@
  *  Utility functions for benchmarking. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 24da0b753b54e781787a0bc28995edbca5aba287..b5109ce8ecd1e117a583f33c3027035eb2daf2a0 100644 (file)
  *  This program is based on work by
  *      Isabella Bierenbaum <bierenbaum@thep.physik.uni-mainz.de> and
  *      Dirk Kreimer <dkreimer@bu.edu>.
- *  For details, please see <http://www.arXiv.org/abs/hep-th/0111192>.
+ *  For details, please see <https://www.arXiv.org/abs/hep-th/0111192>.
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -308,7 +308,7 @@ bool node::operator<(const node &n) const
                return typeid(*vert).before(typeid(*n.vert));
        // Are the indices of the top-level nodes different?
        if (!(*vert==*n.vert))
-               return (vert<n.vert);
+               return (*vert<*n.vert);
        // Are the sets of children different, one by one?
        return (children<n.children);
 }
index 15f11bd2a4060d045f68d149a1171e5f351f8c30..f83de63dcf2459ff48a07a94ddcc447770b11c24 100644 (file)
@@ -7,7 +7,7 @@
  *  after which e should be just a1^2. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 6b08ca45ede57181acd60c99ebe2ecc2085e3c74..fb0f31deb28ae193f7c512a39cb9787e702481e5 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index f024c08a60e5a4ae81cc66c5f634537d6ebab468..6810797031e0b7442589a375d4deddcae2055a9c 100644 (file)
@@ -3,7 +3,7 @@
  *  Some timings on series expansion of the Gamma function around a pole. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/check/time_hashmap.cpp b/check/time_hashmap.cpp
deleted file mode 100644 (file)
index 7657a47..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/** @file time_hashmap.cpp
- *
- *  Timings for exhashmap<> operations. */
-
-/*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "ginac.h"
-#include "timer.h"
-using namespace GiNaC;
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-template <class T>
-static void run_timing(unsigned size, double &time_insert, double &time_find, double &time_erase)
-{
-       vector<symbol> S;
-       T M;
-       timer t;
-
-       S.reserve(size);
-       for (unsigned i=0; i<size; ++i)
-               S.push_back(symbol());
-
-       t.start();
-       for (unsigned i=0; i<size; ++i)
-               M[S[i]] = S[(i+1)%size];
-       time_insert = t.read();
-
-       t.start();
-       for (unsigned i=0; i<size; ++i) {
-               if (!M[S[i]].is_equal(S[(i+1)%size])) {
-                       clog << "map lookup failed" << endl;
-                       return;
-               }
-       }
-       time_find = t.read();
-
-       t.start();
-       for (unsigned i=0; i<size; ++i) {
-               if (M.erase(S[i]) != 1) {
-                       clog << "erasing element " << S[i] << " failed" << endl;
-                       return;
-               }
-       }
-       if (!M.empty()) {
-               clog << "map not empty (size = " << M.size() << ") after erasing all elements" << endl;
-               return;
-       }
-       time_erase = t.read();
-}
-
-
-unsigned time_hashmap()
-{
-       unsigned result = 0;
-
-       cout << "timing hash map operations" << flush;
-
-       unsigned s[] = {10000, 50000, 100000, 500000};
-       vector<unsigned> sizes(s, s+sizeof(s)/sizeof(*s));
-
-       vector<double> times_insert, times_find, times_erase;
-
-       for (vector<unsigned>::const_iterator i = sizes.begin(); i != sizes.end(); ++i) {
-               double time_insert, time_find, time_erase;
-
-               run_timing<exhashmap<ex>>(*i, time_insert, time_find, time_erase);
-
-// If you like, you can compare it with this:
-//             run_timing<std::map<ex, ex, ex_is_less>>(*i, time_insert, time_find, time_erase);
-
-               times_insert.push_back(time_insert);
-               times_find.push_back(time_find);
-               times_erase.push_back(time_erase);
-               cout << '.' << flush;
-       }
-
-       // print the report:
-       cout << endl << "          size:\t";
-       copy(sizes.begin(), sizes.end(), ostream_iterator<unsigned>(cout, "\t"));
-       cout << endl << "      insert/s:\t";
-       copy(times_insert.begin(), times_insert.end(), ostream_iterator<double>(cout, "\t"));
-       cout << endl << "        find/s:\t";
-       copy(times_find.begin(), times_find.end(), ostream_iterator<double>(cout, "\t"));
-       cout << endl << "       erase/s:\t";
-       copy(times_erase.begin(), times_erase.end(), ostream_iterator<double>(cout, "\t"));
-       cout << endl;
-
-       return result;
-}
-
-extern void randomify_symbol_serials();
-
-int main(int argc, char** argv)
-{
-       randomify_symbol_serials();
-       cout << setprecision(2) << showpoint;
-       return time_hashmap();
-}
index e76a4f77484d12e38baf645ffccec70f8395d045..9f40ad2813f4c3c74d863711cb3639c401d32798 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index b6eb9d2c3e4f3a646b60a8294ad34cd8995e0667..356fd67bf45311f5d342caf414532deade2de781 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 69ac0a33dec1eec0026f125904440edc81212465..752b02e6172e3c42b6e3e8dcc70149b90a6cae22 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e843d9509af79f59c1e7c7e4e3ec7267f61870d5..516592ad15667a75be6eebf0539e1ac52ed95733 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 39f022a2cdc0288b41ebf8b8c8ee0eec38739a2c..d8ca7f2bdc6bdb7331bb385cbaa6725191fef3ac 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index bdece2ae369988807ea7819cb95bb3a735ddbf00..a359c2c950790399ad8678899db8473cd244e5da 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 47d5d5cfc227da397647e5c05f59cfb1f9e6fd75..85100b2e4d26cf5fe578648a078af6b8fbe88327 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 59fe14154bfa9d79e5af8f5e1901345350a55fa0..8428d2aa04b6af71de15e08bb5c5ca8128159672 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 7d857923bc7444ef608f2fc8573c5dffe2473e7a..e83383def7c13b02f16e8d933babb1ec09ac68dd 100644 (file)
@@ -4,7 +4,7 @@
  *  by Robert H. Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 75067b96af558a08d1d7e919b4ecbd3e2d72958a..208e22d381e6497e20c4806e9bd3a0cb2bf61bfe 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 68e9ca6f8e02364e0a1f94b4276aaf498d5ff274..64867886f7d673b80568da995349bc9103ef03ef 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 40c614cda88e4e084094eede67ea71abadc60ade..4b0f83b592acb42e3c47e7d6c6d7dbfc7cf6b6c6 100644 (file)
@@ -5,7 +5,7 @@
  *  Fermat-test). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index bf25434888605ac5ea5d905c74ab4bfb94fe43e4..6044a0a6d403e8d067d36db3336fb9bc7ba1c546 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index ea67414cd5b2111cb5f96da8237b0d2792d4492e..9e37b952c45f72ae454aabf1721a3de35d4bafe2 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 241877b769b9e6b6761977908e7ae824bf306161..82a0e4f0499b8cba92f74fa739183239ebd50c78 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 2db723b48a27cf66f84ffd904ac1e566902660dc..15363a519c983ae0eab31b9da904269c5462d126 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 2d508ba9580e46960f4e80cb3e1a509e96808865..947d8f9fe6a472c55b578cb7194cd01aeeb4d1fc 100644 (file)
@@ -4,7 +4,7 @@
  *  Lewis and Michael Wester. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 9224518a05b2584833b7c3d415841e91e7c3f04f..426ed2e972c93e1f88e7d2eb0cb129fd21145936 100644 (file)
@@ -3,7 +3,7 @@
  *  Time the parser. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 6d04e6ad2fc80058b5ae03f335c22ec7f31c07de..236425c5c54054b77344572ca97a6c25cddc1889 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 5467b1115168ad26e473e7a8ece66279356440f8..32701f9fd3dac5f6ae5c26650bcd675c1a7ef63c 100644 (file)
@@ -3,7 +3,7 @@
  *  Time the different GCD algorithms. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 675c1074e59643bca6af0fea8414559d43c0716e..84448a75d3b6f0e6e3fde26d5f31980466e515e1 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index af986553ec67afa3c0019743df4b6f310873c133..4188b7e14555640575b1c83a99114fa11974dc45 100644 (file)
@@ -3,7 +3,7 @@
  *  A simple stop watch class. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 29b77c422a9bc6defe87a23bbb2ad58802136738..641ae43f84bcf717d6e4773e177a5571541b0551 100644 (file)
@@ -3,7 +3,7 @@
  *  A simple stop watch class. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/cmake/ginac-config.cmake.in b/cmake/ginac-config.cmake.in
new file mode 100644 (file)
index 0000000..ba6e5b3
--- /dev/null
@@ -0,0 +1,9 @@
+get_filename_component(ginac_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+include(CMakeFindDependencyMacro)
+find_package(CLN 1.2.2 REQUIRED)
+
+if (NOT TARGET ginac::ginac)
+       include("${ginac_CMAKE_DIR}/ginac-targets.cmake")
+endif()
+
+set(ginac_LIBRARIES ginac::ginac)
index ee5fc5ca628206542d69d87b920e6c5e0f4bd760..1f07bc9ab0a138a067ecaf841445e3ccbc92bf56 100644 (file)
@@ -116,3 +116,26 @@ include(FindPackageHandleStandardArgs)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(CLN REQUIRED_VARS CLN_LIBRARIES CLN_INCLUDE_DIR
                                      VERSION_VAR CLN_VERSION)
 
+if (CLN_FOUND AND NOT TARGET cln::cln)
+       set(_found_shared_libcln FALSE)
+       get_filename_component(_libcln_suffix ${CLN_LIBRARIES} EXT)
+       if (_libcln_suffix STREQUAL ${CMAKE_STATIC_LIBRARY_SUFFIX})
+               # XXX: msvc uses the same suffix for both static and import libraries
+               add_library(cln::cln STATIC IMPORTED)
+       else()
+               set(_found_shared_libcln TRUE)
+               add_library(cln::cln SHARED IMPORTED)
+       endif()
+       set_target_properties(cln::cln PROPERTIES
+               INTERFACE_INCLUDE_DIRECTORIES ${CLN_INCLUDE_DIR}
+       )
+       if (WIN32 AND _found_shared_libcln)
+               set_target_properties(cln::cln PROPERTIES
+                       IMPORTED_IMPLIB ${CLN_LIBRARIES}
+               )
+       else()
+               set_target_properties(cln::cln PROPERTIES
+                       IMPORTED_LOCATION ${CLN_LIBRARIES}
+               )
+       endif()
+endif()
diff --git a/config/.gitignore b/config/.gitignore
new file mode 100644 (file)
index 0000000..cc7ddb4
--- /dev/null
@@ -0,0 +1,14 @@
+compile
+config.guess
+config.h
+config.h.in
+config.sub
+depcomp
+install-sh
+ltmain.sh
+mdate-sh
+missing
+stamp-h1
+test-driver
+texinfo.tex
+ylwrap
index a3e25c844d15f579f0456df434c7f698487c86f7..1e2595ff5907067b1aafb3095298ec02eab5adb7 100755 (executable)
@@ -2,7 +2,7 @@
 # Output a system dependent set of variables, describing how to set the
 # run time search path of shared libraries in an executable.
 #
-#   Copyright 1996-2015 Free Software Foundation, Inc.
+#   Copyright 1996-2023 Free Software Foundation, Inc.
 #   Taken from GNU libtool, 2001
 #   Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
 #
@@ -371,7 +371,7 @@ else
       hardcode_direct=yes
       hardcode_minus_L=yes
       ;;
-    freebsd* | dragonfly*)
+    freebsd* | dragonfly* | midnightbsd*)
       hardcode_libdir_flag_spec='-R$libdir'
       hardcode_direct=yes
       ;;
@@ -547,7 +547,7 @@ case "$host_os" in
   freebsd[23].*)
     library_names_spec='$libname$shrext$versuffix'
     ;;
-  freebsd* | dragonfly*)
+  freebsd* | dragonfly* | midnightbsd*)
     library_names_spec='$libname$shrext'
     ;;
   gnu*)
index 3c2311b6f15e673d47492d8cec5ea2ed973035bb..96c89358765205f1d815d2dc9162a23223158818 100644 (file)
@@ -11,8 +11,8 @@ m4_define([ginac_lt_current], GINAC_GET_LTVERSION([CURRENT]))
 m4_define([ginac_lt_age], GINAC_GET_LTVERSION([AGE]))
 m4_define([ginac_lt_revision], GINAC_GET_LTVERSION([REVISION]))
 
-AC_INIT([GiNaC], ginac_version, [ginac-list@ginac.de], [ginac], [http://www.ginac.de/])
-AC_PREREQ(2.59)
+AC_INIT([GiNaC], [ginac_version], [ginac-list@ginac.de], [ginac], [https://www.ginac.de/])
+AC_PREREQ([2.59])
 AC_CONFIG_SRCDIR(ginac/basic.cpp)
 AC_CONFIG_AUX_DIR([config])
 AC_CONFIG_HEADERS([config/config.h])
@@ -28,8 +28,8 @@ dnl Check for the compiler and all the utilities needed for the build.
 AC_PROG_CXX
 AC_PROG_CXXCPP
 AC_PROG_INSTALL
-AM_PROG_LIBTOOL
-AC_PROG_LEX
+LT_INIT
+AC_PROG_LEX([yywrap])
 AC_PROG_YACC
 AC_PATH_PROG(YACCEXE, $YACC, "")
 AS_IF([test "x$LEX" = "x:" -a ! -f $srcdir/ginsh/ginsh_lexer.cpp],
@@ -41,9 +41,6 @@ dnl Switch to C++ language mode for the following libraries and headers.
 AC_LANG([C++])
 AX_CXX_COMPILE_STDCXX([11])
 
-dnl Make sure all the necessary standard headers are installed on the system.
-GINAC_STD_CXX_HEADERS
-
 dnl We need to have CLN installed.
 PKG_CHECK_MODULES(CLN, cln >= 1.2.2)
 AC_LIB_LINKFLAGS_FROM_LIBS([CLN_RPATH], [$CLN_LIBS])
@@ -60,9 +57,8 @@ AC_CHECK_HEADERS(unistd.h)
 GINAC_HAVE_RUSAGE
 GINAC_READLINE
 dnl Python is necessary for building function.{cpp,h}
-AC_PATH_PROG(PYTHON, python, "")
-AS_IF([test -z "$PYTHON" -a ! -f "$srcdir/ginac/function.cpp"],
-      [AC_MSG_ERROR([GiNaC will not compile because Python is missing])])
+AM_PATH_PYTHON([2.7],,
+               [AC_MSG_ERROR([GiNaC will not compile because Python is missing])])
 
 dnl Check for dl library (needed for GiNaC::compile).
 GINAC_EXCOMPILER
@@ -78,7 +74,7 @@ AC_PATH_PROG(PDFLATEX, pdflatex, "")
 AC_PATH_PROG(MAKEINDEX, makeindex, "")
 AC_PATH_PROG(MAKEINFO, makeinfo, "")
 AC_PATH_PROG(DVIPS, dvips, "")
-AM_CONDITIONAL(CONFIG_TEX, [test ! \( -z "$LATEX" -o -z $"PDFLATEX" -o -z "$MAKEINDEX" -o -z "$DVIPS" \)])
+AM_CONDITIONAL(CONFIG_TEX, [test ! \( -z "$LATEX" -o -z "$PDFLATEX" -o -z "$MAKEINDEX" -o -z "$DVIPS" \)])
 AC_PATH_PROG(FIG2DEV, fig2dev, "")
 AM_CONDITIONAL(CONFIG_FIG2DEV, [test ! -z "$FIG2DEV"])
 AS_IF([test -z "$FIG2DEV" -o -z "$MAKEINFO"],
index e1416d31141b9f231db418030c91b9dfb0134dce..e38e2a198ab2a5920ee78d57223fdd97112e8734 100644 (file)
@@ -26,7 +26,7 @@ macro(add_info_file thename)
        add_custom_target(${thename}_html DEPENDS ${${thename}_HTML})
        add_dependencies(info ${thename}_info)
        add_dependencies(html ${thename}_html)
-       install(FILES ${${thename}_INFO} DESTINATION "${SHARE_INSTALL_PREFIX}/info")
+       install(FILES ${${thename}_INFO} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/info")
 endmacro()
 
 macro(pdflatex_process texfile)
@@ -35,7 +35,6 @@ macro(pdflatex_process texfile)
        set(_idx ${_dirname}/${_basename}.idx)
        set(_ind ${_dirname}/${_basename}.ind)
        set(_pdf ${_dirname}/${_basename}.pdf)
-       set(_fixupind ${CMAKE_SOURCE_DIR}/scripts/fixupind.py)
        add_custom_command(
                OUTPUT ${_idx}
                COMMAND ${PDFLATEX_COMPILER} ${texfile}
@@ -45,7 +44,6 @@ macro(pdflatex_process texfile)
        add_custom_command(
                OUTPUT ${_ind}
                COMMAND ${MAKEINDEX_COMPILER} ${_idx}
-               COMMAND python ${_fixupind} ${_idx}
                WORKING_DIRECTORY ${_dirname}
                DEPENDS ${texfile} ${_idx}
                COMMENT "MAKEINDEX ${_basename}.idx")
diff --git a/doc/examples/.gitignore b/doc/examples/.gitignore
new file mode 100644 (file)
index 0000000..b9e3b6e
--- /dev/null
@@ -0,0 +1,3 @@
+*.html
+*.info
+*.txt
index 851c61ce4a59070ccf9f345cddeb504725612455..ea5f64d7619f39d74a93e4b82d069bb4d8fc7d54 100644 (file)
@@ -1 +1,34 @@
-add_info_file(ginac-examples)
+cmake_minimum_required(VERSION 3.1)
+
+project(GiNaC_examples)
+
+if (TARGET ginac)
+       add_info_file(ginac-examples)
+endif()
+
+if (NOT TARGET ginac AND EXISTS ${CMAKE_CURRENT_LIST_DIR}/ginac/CMakeLists.txt)
+       add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/ginac ${CMAKE_CURRENT_BINARY_DIR}/ginac)
+endif()
+
+if (NOT TARGET ginac)
+       find_package(ginac REQUIRED 1.7.0)
+endif()
+
+add_executable(archive1 archive1.cpp)
+target_link_libraries(archive1 ginac::ginac)
+
+add_executable(compile1 compile1.cpp)
+target_link_libraries(compile1 ginac::ginac)
+
+# XXX: compile2 example uses the Cuba library (http://www.feynarts.de/cuba)
+# add_executable(compile2 compile2.cpp)
+# target_link_libraries(compile2 ginac::ginac)
+
+add_executable(compile3 compile3.cpp)
+target_link_libraries(compile3 ginac::ginac)
+
+add_executable(mystring mystring.cpp)
+target_link_libraries(mystring ginac::ginac)
+
+add_executable(derivative derivative.cpp)
+target_link_libraries(derivative ginac::ginac)
index 472a2a163eb2cdfd346148f6c092008e04c7a235..9c66c7317be988e6766baad3bd8d22243b652f0f 100644 (file)
@@ -17,3 +17,30 @@ all: $(EXFILES)
 CLEANFILES = $(TXT) $(HTML)
 
 EXTRA_DIST = $(EXFILES) CMakeLists.txt
+
+AM_CPPFLAGS = -I$(srcdir)/../../ginac -I../../ginac -DIN_GINAC
+
+noinst_PROGRAMS = archive1 \
+                 compile1 \
+                 compile3 \
+                 mystring \
+                 derivative
+
+archive1_SOURCES = archive1.cpp
+archive1_LDADD = ../../ginac/libginac.la
+
+compile1_SOURCES = compile1.cpp
+compile1_LDADD = ../../ginac/libginac.la
+
+# compile2 example uses the Cuba library: (http://www.feynarts.de)
+# compile2_SOURCES = compile2.cpp
+# compile2_LDADD = ../../ginac/libginac.la
+
+compile3_SOURCES = compile3.cpp
+compile3_LDADD = ../../ginac/libginac.la
+
+mystring_SOURCES = mystring.cpp
+mystring_LDADD = ../../ginac/libginac.la
+
+derivative_SOURCES = derivative.cpp
+derivative_LDADD = ../../ginac/libginac.la
index c20db620a71d16e7305ae36c23deb7122e274e40..611a15dcfa4493a9e82a8a7069621f139a2ad951 100644 (file)
@@ -3,8 +3,13 @@
  */
 
 #include <fstream>
-using namespace std;
+
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
 #include <ginac/ginac.h>
+#endif
+using namespace std;
 using namespace GiNaC;
 
 int main()
@@ -32,8 +37,7 @@ int main()
        ifstream in("foobar.gar");
        in >> a2;
 
-       lst syms;
-       syms = x, y;
+       lst syms = {x, y};
 
        ex ex1 = a2.unarchive_ex(syms, "foo");
        ex ex2 = a2.unarchive_ex(syms, "the second one");
index c63b9ca022bd2f6bf5dfae75f1c5dc25ef58e376..8734cdec9ba0cf22f66595dd7785ce09ca6a063b 100644 (file)
@@ -1,7 +1,11 @@
 #include <ctime>
 #include <iostream>
-using namespace std;
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
 #include <ginac/ginac.h>
+#endif
+using namespace std;
 using namespace GiNaC;
 
 /*
@@ -36,7 +40,7 @@ int main()
 
        // First using compile_ex
        {
-               double result;
+               double result = 0.0;
                double point = 0.2;
                start = clock();
                for (int i=0; i<100000; ++i) {
@@ -54,7 +58,7 @@ int main()
 
        // Then without compile_ex
        {
-               ex result;
+               ex result = 0.0;
                ex point = 0.2;
                start = clock();
                for (int i=0; i<100000; ++i) {
index faff99cc9033b6c4379b1aef178d662fe459f921..0854e72234793c393064817de217a27d5ad7ec36 100644 (file)
@@ -1,10 +1,15 @@
 #include <iostream>
-using namespace std;
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
 #include <ginac/ginac.h>
-using namespace GiNaC;
+#endif
 // Yes, we are using CUBA (should be installed on the system!)
 #include <cuba.h>
 
+using namespace std;
+using namespace GiNaC;
+
 /*
  * Demonstrates the use of compile_ex with the CUBA library.
  *
index 993c3b9ff12aaa369e53376c293b0c228081dca3..c0e5209f5f2ff6837e59eea6dbc77b5326c828ad 100644 (file)
@@ -1,7 +1,11 @@
 #include <ctime>
 #include <iostream>
-using namespace std;
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
 #include <ginac/ginac.h>
+#endif
+using namespace std;
 using namespace GiNaC;
 
 /*
index c1a09b993daa342e3bc722466a6c4b75beadedb1..3b845c05daf42d162097abb1342beca2b838e341 100644 (file)
@@ -5,7 +5,11 @@
 #include <iostream>
 #include <string>
 #include <stdexcept>
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
 #include <ginac/ginac.h>
+#endif
 using namespace std;
 using namespace GiNaC;
 
index 627bb3f87865bb2c79174b0d0e3012fbaad4b124..4a09525aa5c623058f05f2f7d51d4bd5370fb04c 100644 (file)
@@ -28,7 +28,7 @@
  * The value of g is taken to be equal to the order N.
  *
  * More details can be found at Wikipedia:
- * http://en.wikipedia.org/wiki/Lanczos_approximation.
+ * https://en.wikipedia.org/wiki/Lanczos_approximation.
  *
  * (C) 2006 Chris Dams
  *
@@ -48,6 +48,7 @@
  * MA  02110-1301 USA
  */
 
+#include <getopt.h>
 #include <vector>
 #include <cstddef> // for size_t
 #include <iostream>
index bcbf96a889c84e748bce606bae5b18f48ad1a3d5..655fe825f93b7d5b3ffe96d8ed7252aeeb44b3c4 100644 (file)
@@ -4,9 +4,12 @@
 #include <iostream>
 #include <string>   
 #include <stdexcept>
-using namespace std;
-
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
 #include <ginac/ginac.h>
+#endif
+using namespace std;
 using namespace GiNaC;
 
 class mystring : public basic
@@ -14,7 +17,7 @@ class mystring : public basic
        GINAC_DECLARE_REGISTERED_CLASS(mystring, basic)
 public:
        mystring(const string &s);
-       ex eval(int level) const override;
+       ex eval() const override;
 private:
        string str;
 
@@ -54,7 +57,7 @@ void mystring::do_print(const print_context &c, unsigned level) const
  * evaluation: all strings automatically converted to lowercase with
  * non-alphabetic characters stripped, and empty strings removed
  */
-ex mystring::eval(int level) const
+ex mystring::eval() const
 {
        string new_str;
        for (size_t i=0; i<str.length(); i++) {
diff --git a/doc/reference/.gitignore b/doc/reference/.gitignore
new file mode 100644 (file)
index 0000000..f2453a0
--- /dev/null
@@ -0,0 +1,2 @@
+Doxy*
+Doxy*!.in!
index e8de75474b6643e00b0fd7f0f5e6c87807aab804..0a12741b21e137e13074e617863030347d164440 100644 (file)
@@ -1,8 +1,8 @@
 <hr>
 <small><i>This page is part of the <b><a
-href="http://www.ginac.de/">GiNaC</a></b>
+href="https://www.ginac.de/">GiNaC</a></b>
 developer's reference. It was generated automatically by <a
-href="http://www.stack.nl/~dimitri/doxygen/index.html">doxygen</a>. For
+href="https://www.doxygen.nl/">doxygen</a>. For
 an introduction, see the <a href="../tutorial/">tutorial</a>.</i></small>
 </body>
 </html>
index 445eeb729a4535d2a8e74836435326d89d6189dc..5ad8a0006616e8ec1b1d9536fd7a226f6e638d8f 100644 (file)
@@ -53,7 +53,6 @@ pdflatex/reference.pdf: pdflatex/reference.tex
                cd pdflatex; \
          ${PDFLATEX} reference.tex ;\
          ${MAKEINDEX} reference.idx ;\
-         ${PYTHON} $(abs_top_srcdir)/scripts/fixupind.py reference.ind; \
          ${PDFLATEX} reference.tex
 
 reference.dvi: latex latex/reference.dvi
diff --git a/doc/tutorial/.gitignore b/doc/tutorial/.gitignore
new file mode 100644 (file)
index 0000000..5556e56
--- /dev/null
@@ -0,0 +1,3 @@
+*.info
+stamp-vti
+version.texi
index a34595850841d5359a3bd1f1e3090ae046dd9862..52c5828e95a178e8d2de18d3e66d3fb3c7fb2adb 100644 (file)
@@ -24,7 +24,7 @@
 This is a tutorial that documents GiNaC @value{VERSION}, an open
 framework for symbolic computation within the C++ programming language.
 
-Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
 
 Permission is granted to make and distribute verbatim copies of
 this manual provided the copyright notice and this permission notice
@@ -48,11 +48,11 @@ notice identical to this one.
 @title GiNaC @value{VERSION}
 @subtitle An open framework for symbolic computation within the C++ programming language
 @subtitle @value{UPDATED}
-@author @uref{http://www.ginac.de}
+@author @uref{https://www.ginac.de}
 
 @page
 @vskip 0pt plus 1filll
-Copyright @copyright{} 1999-2019 Johannes Gutenberg University Mainz, Germany
+Copyright @copyright{} 1999-2024 Johannes Gutenberg University Mainz, Germany
 @sp 2
 Permission is granted to make and distribute verbatim copies of
 this manual provided the copyright notice and this permission notice
@@ -126,7 +126,7 @@ hand-made documentation like this one is difficult to keep in sync with
 the development, the actual documentation is inside the sources in the
 form of comments.  That documentation may be parsed by one of the many
 Javadoc-like documentation systems.  If you fail at generating it you
-may access it from @uref{http://www.ginac.de/reference/, the GiNaC home
+may access it from @uref{https://www.ginac.de/reference/, the GiNaC home
 page}.  It is an invaluable resource not only for the advanced user who
 wishes to extend the system (or chase bugs) but for everybody who wants
 to comprehend the inner workings of GiNaC.  This little tutorial on the
@@ -135,7 +135,7 @@ the near future.
 
 @section License
 The GiNaC framework for symbolic computation within the C++ programming
-language is Copyright @copyright{} 1999-2019 Johannes Gutenberg
+language is Copyright @copyright{} 1999-2024 Johannes Gutenberg
 University Mainz, Germany.
 
 This program is free software; you can redistribute it and/or
@@ -372,8 +372,8 @@ lambda^2-3*lambda+11
 @end example
 
 Multivariate polynomials and rational functions may be expanded,
-collected and normalized (i.e. converted to a ratio of two coprime 
-polynomials):
+collected, factorized, and normalized (i.e. converted to a ratio of
+two coprime polynomials):
 
 @example
 > a = x^4 + 2*x^2*y^2 + 4*x^3*y + 12*x*y^3 - 3*y^4;
@@ -382,6 +382,8 @@ polynomials):
 4*x*y-y^2+x^2
 > expand(a*b);
 8*x^5*y+17*x^4*y^2+43*x^2*y^4-24*x*y^5+16*x^3*y^3+3*y^6+x^6
+> factor(%);
+(4*x*y+x^2-y^2)^2*(x^2+3*y^2)
 > collect(a+b,x);
 4*x^3*y-y^2-3*y^4+(12*y^3+4*y)*x+x^4+x^2*(1+2*y^2)
 > collect(a+b,y);
@@ -390,6 +392,9 @@ polynomials):
 3*y^2+x^2
 @end example
 
+Here we have made use of the @command{ginsh}-command @code{%} to pop the
+previously evaluated element from @command{ginsh}'s internal stack.
+
 You can differentiate functions and expand them as Taylor or Laurent
 series in a very natural syntax (the second argument of @code{series} is
 a relation defining the evaluation point, the third specifies the
@@ -414,9 +419,6 @@ x^(-1)-0.5772156649015328606+(0.9890559953279725555)*x
 -Euler-1/12+Order((x-1/2*Pi)^3)
 @end example
 
-Here we have made use of the @command{ginsh}-command @code{%} to pop the
-previously evaluated element from @command{ginsh}'s internal stack.
-
 Often, functions don't have roots in closed form.  Nevertheless, it's
 quite easy to compute a solution numerically, to arbitrary precision:
 
@@ -484,7 +486,7 @@ required for the configuration, it can be downloaded from
 @uref{http://pkg-config.freedesktop.org}.
 Last but not least, the CLN library
 is used extensively and needs to be installed on your system.
-Please get it from @uref{http://www.ginac.de/CLN/} (it is licensed under
+Please get it from @uref{https://www.ginac.de/CLN/} (it is licensed under
 the GPL) and install it prior to trying to install GiNaC.  The configure
 script checks if it can find it and if it cannot, it will refuse to
 continue.
@@ -717,7 +719,6 @@ meta-class for storing all mathematical objects.
 * Matrices::                     Matrices.
 * Indexed objects::              Handling indexed quantities.
 * Non-commutative objects::      Algebras with non-commutative products.
-* Hash maps::                    A faster alternative to std::map<>.
 @end menu
 
 
@@ -1193,7 +1194,7 @@ For storing numerical things, GiNaC uses Bruno Haible's library CLN.
 The classes therein serve as foundation classes for GiNaC.  CLN stands
 for Class Library for Numbers or alternatively for Common Lisp Numbers.
 In order to find out more about CLN's internals, the reader is referred to
-the documentation of that library.  @inforef{Introduction, , cln}, for
+the documentation of that library.  @xref{Top,,, cln, The CLN Manual}, for
 more information. Suffice to say that it is by itself build on top of
 another library, the GNU Multiple Precision library GMP, which is an
 extremely fast library for arbitrary long integers and rationals as well
@@ -1865,13 +1866,31 @@ substitutions.  They are also used as arguments to the @code{ex::series}
 method, where the left hand side of the relation specifies the variable
 to expand in and the right hand side the expansion point.  They can also
 be used for creating systems of equations that are to be solved for
-unknown variables.  But the most common usage of objects of this class
+unknown variables.
+
+But the most common usage of objects of this class
 is rather inconspicuous in statements of the form @code{if
 (expand(pow(a+b,2))==a*a+2*a*b+b*b) @{...@}}.  Here, an implicit
 conversion from @code{relational} to @code{bool} takes place.  Note,
 however, that @code{==} here does not perform any simplifications, hence
 @code{expand()} must be called explicitly.
 
+Simplifications of
+relationals may be more efficient if preceded by a call to
+@example
+ex relational::canonical() const
+@end example
+which returns an equivalent relation with the zero
+right-hand side. For example:
+@example
+possymbol p("p");
+relational rel = (p >= (p*p-1)/p);
+if (ex_to<relational>(rel.canonical().normal()))
+       cout << "correct inequality" << endl;
+@end example
+However, a user shall not expect that any inequality can be fully
+resolved by GiNaC.
+
 @node Integrals, Matrices, Relations, Basic concepts
 @c    node-name, next, previous, up
 @section Integrals
@@ -2987,7 +3006,7 @@ one form for @samp{F} and explicitly multiply it with a matrix representation
 of the metric tensor.
 
 
-@node Non-commutative objects, Hash maps, Indexed objects, Basic concepts
+@node Non-commutative objects, Methods and functions, Indexed objects, Basic concepts
 @c    node-name, next, previous, up
 @section Non-commutative objects
 
@@ -3223,7 +3242,8 @@ element, which defaults to 4.
 The @code{dirac_trace()} function is a linear functional that is equal to the
 ordinary matrix trace only in @math{D = 4} dimensions. In particular, the
 functional is not cyclic in
-@tex $D \ne 4$
+@tex
+$D \ne 4$
 @end tex
 @ifnottex
 @math{D != 4}
@@ -3234,7 +3254,8 @@ expressions containing @samp{gamma5}, so it's not a proper trace. This
 @cite{The Role of gamma5 in Dimensional Regularization} (@ref{Bibliography}).
 
 The value of the trace itself is also usually different in 4 and in
-@tex $D \ne 4$
+@tex
+$D \ne 4$
 @end tex
 @ifnottex
 @math{D != 4}
@@ -3307,15 +3328,16 @@ You can use this to compare two expressions or for further simplifications:
 @subsubsection A generic Clifford algebra
 
 A generic Clifford algebra, i.e. a
-@tex $2^n$
+@tex
+$2^n$
 @end tex
 @ifnottex
 2^n
 @end ifnottex
-dimensional algebra with
-generators 
-@tex $e_k$
-@end tex 
+dimensional algebra with generators
+@tex
+$e_k$
+@end tex
 @ifnottex
 e_k
 @end ifnottex
@@ -3771,43 +3793,7 @@ example:
 @end example
 
 
-@node Hash maps, Methods and functions, Non-commutative objects, Basic concepts
-@c    node-name, next, previous, up
-@section Hash Maps
-@cindex hash maps
-@cindex @code{exhashmap} (class)
-
-For your convenience, GiNaC offers the container template @code{exhashmap<T>}
-that can be used as a drop-in replacement for the STL
-@code{std::map<ex, T, ex_is_less>}, using hash tables to provide faster,
-typically constant-time, element look-up than @code{map<>}.
-
-@code{exhashmap<>} supports all @code{map<>} members and operations, with the
-following differences:
-
-@itemize @bullet
-@item
-no @code{lower_bound()} and @code{upper_bound()} methods
-@item
-no reverse iterators, no @code{rbegin()}/@code{rend()}
-@item 
-no @code{operator<(exhashmap, exhashmap)}
-@item
-the comparison function object @code{key_compare} is hardcoded to
-@code{ex_is_less}
-@item
-the constructor @code{exhashmap(size_t n)} allows specifying the minimum
-initial hash table size (the actual table size after construction may be
-larger than the specified value)
-@item
-the method @code{size_t bucket_count()} returns the current size of the hash
-table
-@item 
-@code{insert()} and @code{erase()} operations invalidate all iterators
-@end itemize
-
-
-@node Methods and functions, Information about expressions, Hash maps, Top
+@node Methods and functions, Information about expressions, Non-commutative objects, Top
 @c    node-name, next, previous, up
 @chapter Methods and functions
 @cindex polynomial
@@ -3861,6 +3847,7 @@ avoided.
 * Symmetrization::
 * Built-in functions::              List of predefined mathematical functions.
 * Multiple polylogarithms::
+* Iterated integrals::
 * Complex expressions::
 * Solving linear systems of equations::
 * Input/output::                    Input and output of expressions.
@@ -4889,7 +4876,7 @@ presented this would be impractical.
 One solution to this dilemma is the @dfn{Visitor} design pattern,
 which is implemented in GiNaC (actually, Robert Martin's Acyclic Visitor
 variation, described in detail in
-@uref{http://objectmentor.com/publications/acv.pdf}). Instead of adding
+@uref{https://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf}). Instead of adding
 virtual functions to the class hierarchy to implement operations, GiNaC
 provides a single "bouncing" method @code{accept()} that takes an instance
 of a special @code{visitor} class and redirects execution to the one
@@ -5395,6 +5382,27 @@ some care with subsequent processing of the result:
 Note also, how factors with the same exponents are not fully factorized
 with this method.
 
+@subsection Square-free partial fraction decomposition
+@cindex square-free partial fraction decomposition
+@cindex partial fraction decomposition
+@cindex @code{sqrfree_parfrac()}
+
+GiNaC also supports square-free partial fraction decomposition of
+rational functions:
+@example
+ex sqrfree_parfrac(const ex & a, const symbol & x);
+@end example
+It is called square-free because it assumes a square-free
+factorization of the input's denominator:
+@example
+    ...
+    symbol x("x");
+
+    ex rat = (x-4)/(pow(x,2)*(x+2));
+    cout << sqrfree_parfrac(rat, x) << endl;
+     // -> -2*x^(-2)+3/2*x^(-1)-3/2*(2+x)^(-1)
+@end example
+
 @subsection Polynomial factorization
 @cindex factorization
 @cindex polynomial factorization
@@ -5716,7 +5724,7 @@ using namespace GiNaC;
 ex machin_pi(int degr)
 @{
     symbol x;
-    ex pi_expansion = series_to_poly(atan(x).series(x,degr));
+    ex pi_expansion = series_to_poly(atan(x).series(x==0,degr));
     ex pi_approx = 16*pi_expansion.subs(x==numeric(1,5))
                    -4*pi_expansion.subs(x==numeric(1,239));
     return pi_approx;
@@ -5908,6 +5916,12 @@ GiNaC contains the following predefined mathematical functions:
 @cindex @code{zeta()}
 @item @code{zetaderiv(n, x)}
 @tab derivatives of Riemann's zeta function
+@item @code{iterated_integral(a, y)}
+@tab iterated integral
+@cindex @code{iterated_integral()}
+@item @code{iterated_integral(a, y, N)}
+@tab iterated integral with explicit truncation parameter
+@cindex @code{iterated_integral()}
 @item @code{tgamma(x)}
 @tab gamma function
 @cindex @code{tgamma()}
@@ -5923,6 +5937,12 @@ GiNaC contains the following predefined mathematical functions:
 @cindex @code{psi()}
 @item @code{psi(n, x)}
 @tab derivatives of psi function (polygamma functions)
+@item @code{EllipticK(x)}
+@tab complete elliptic integral of the first kind
+@cindex @code{EllipticK()}
+@item @code{EllipticE(x)}
+@tab complete elliptic integral of the second kind
+@cindex @code{EllipticE()}
 @item @code{factorial(n)}
 @tab factorial function @math{n!}
 @cindex @code{factorial()}
@@ -6003,7 +6023,7 @@ GiNaC uses the opposite order: firstly expands the function and then its
 argument. Of course, a user can fine-tune this behavior by sequential
 calls of several @code{expand()} methods with desired flags.
 
-@node Multiple polylogarithms, Complex expressions, Built-in functions, Methods and functions
+@node Multiple polylogarithms, Iterated integrals, Built-in functions, Methods and functions
 @c    node-name, next, previous, up
 @subsection Multiple polylogarithms
 
@@ -6017,7 +6037,7 @@ calls of several @code{expand()} methods with desired flags.
 The multiple polylogarithm is the most generic member of a family of functions,
 to which others like the harmonic polylogarithm, Nielsen's generalized
 polylogarithm and the multiple zeta value belong.
-Everyone of these functions can also be written as a multiple polylogarithm with specific
+Each of these functions can also be written as a multiple polylogarithm with specific
 parameters. This whole family of functions is therefore often referred to simply as
 multiple polylogarithms, containing @code{Li}, @code{G}, @code{H}, @code{S} and @code{zeta}.
 The multiple polylogarithm itself comes in two variants: @code{Li} and @code{G}. While
@@ -6186,7 +6206,71 @@ J.Borwein, D.Bradley, D.Broadhurst, P.Lisonek, Trans.Amer.Math.Soc. 353/3 (2001)
 @cite{Numerical Evaluation of Multiple Polylogarithms}, 
 J.Vollinga, S.Weinzierl, hep-ph/0410259
 
-@node Complex expressions, Solving linear systems of equations, Multiple polylogarithms, Methods and functions
+@node Iterated integrals, Complex expressions, Multiple polylogarithms, Methods and functions
+@c    node-name, next, previous, up
+@subsection Iterated integrals
+
+Multiple polylogarithms are a particular example of iterated integrals.
+An iterated integral is defined by the function @code{iterated_integral(a,y)}.
+The variable @code{y} gives the upper integration limit for the outermost integration, by convention the lower integration limit is always set to zero.
+The variable @code{a} must be a GiNaC @code{lst} containing sub-classes of @code{integration_kernel} as elements.
+The depth of the iterated integral corresponds to the number of elements of @code{a}.
+The available integrands for iterated integrals are
+(for a more detailed description the user is referred to the publications listed at the end of this section)
+@cartouche
+@multitable @columnfractions .40 .60
+@item @strong{Class} @tab @strong{Description}
+@item @code{integration_kernel()}
+@tab Base class, represents the one-form @math{dy}
+@cindex @code{integration_kernel()}
+@item @code{basic_log_kernel()}
+@tab Logarithmic one-form @math{dy/y}
+@cindex @code{basic_log_kernel()}
+@item @code{multiple_polylog_kernel(z_j)}
+@tab The one-form @math{dy/(y-z_j)}
+@cindex @code{multiple_polylog_kernel()}
+@item @code{ELi_kernel(n, m, x, y)}
+@tab The one form @math{ELi_{n;m}(x;y;q) dq/q}
+@cindex @code{ELi_kernel()}
+@item @code{Ebar_kernel(n, m, x, y)}
+@tab The one form @math{\overline{E}_{n;m}(x;y;q) dq/q}
+@cindex @code{Ebar_kernel()}
+@item @code{Kronecker_dtau_kernel(k, z_j, K, C_k)}
+@tab The one form @math{C_k K (k-1)/(2 \pi i)^k g^{(k)}(z_j,K \tau) dq/q}
+@cindex @code{Kronecker_dtau_kernel()}
+@item @code{Kronecker_dz_kernel(k, z_j, tau, K, C_k)}
+@tab The one form @math{C_k (2 \pi i)^{2-k} g^{(k-1)}(z-z_j,K \tau) dz}
+@cindex @code{Kronecker_dz_kernel()}
+@item @code{Eisenstein_kernel(k, N, a, b, K, C_k)}
+@tab The one form @math{C_k E_{k,N,a,b,K}(\tau) dq/q}
+@cindex @code{Eisenstein_kernel()}
+@item @code{Eisenstein_h_kernel(k, N, r, s, C_k)}
+@tab The one form @math{C_k h_{k,N,r,s}(\tau) dq/q}
+@cindex @code{Eisenstein_h_kernel()}
+@item @code{modular_form_kernel(k, P, C_k)}
+@tab The one form @math{C_k P dq/q}
+@cindex @code{modular_form_kernel()}
+@item @code{user_defined_kernel(f, y)}
+@tab The one form @math{f(y) dy}
+@cindex @code{user_defined_kernel()}
+@end multitable
+@end cartouche
+All parameters are assumed to be such that all integration kernels have a convergent Laurent expansion
+around zero with at most a simple pole at zero.
+The iterated integral may also be called with an optional third parameter
+@code{iterated_integral(a,y,N_trunc)}, in which case the numerical evaluation will truncate the series
+expansion at order @code{N_trunc}.
+
+The classes @code{Eisenstein_kernel()}, @code{Eisenstein_h_kernel()} and @code{modular_form_kernel()}
+provide a method @code{q_expansion_modular_form(q, order)}, which can used to obtain the q-expansion
+of @math{E_{k,N,a,b,K}(\tau)}, @math{h_{k,N,r,s}(\tau)} or @math{P} to the specified order.
+
+Useful publications:
+
+@cite{Numerical evaluation of iterated integrals related to elliptic Feynman integrals}, 
+M.Walden, S.Weinzierl, arXiv:2010.05271
+
+@node Complex expressions, Solving linear systems of equations, Iterated integrals, Methods and functions
 @c    node-name, next, previous, up
 @section Complex expressions
 @c
@@ -6731,8 +6815,8 @@ expression a unique name:
 
 @example
 #include <fstream>
-using namespace std;
 #include <ginac/ginac.h>
+using namespace std;
 using namespace GiNaC;
 
 int main()
@@ -7648,9 +7732,8 @@ product in a C++ @code{struct}:
 
 @example
 #include <iostream>
-using namespace std;
-
 #include <ginac/ginac.h>
+using namespace std;
 using namespace GiNaC;
 
 struct sprod_s @{
@@ -8042,9 +8125,8 @@ as follows:
 #include <iostream>
 #include <string>   
 #include <stdexcept>
-using namespace std;
-
 #include <ginac/ginac.h>
+using namespace std;
 using namespace GiNaC;
 @end example
 
@@ -8623,9 +8705,9 @@ inserted.  But it may be useful to remember that this is not what
 happens.  Knowing this will enable you to write much more efficient
 code.  If you still have an uncertain feeling with copy-on-write
 semantics, we recommend you have a look at the
-@uref{http://www.parashift.com/c++-faq-lite/, C++-FAQ lite} by
-Marshall Cline.  Chapter 16 covers this issue and presents an
-implementation which is pretty close to the one in GiNaC.
+@uref{https://isocpp.org/faq, C++-FAQ's} chapter on memory management.
+It covers this issue and presents an implementation which is pretty
+close to the one in GiNaC.
 
 
 @node Internal representation of products and sums, Package tools, Expressions are reference counted, Internal structures
@@ -8724,12 +8806,12 @@ program use @footnote{If GiNaC is installed into some non-standard
 directory @var{prefix} one should set the @var{PKG_CONFIG_PATH}
 environment variable to @var{prefix}/lib/pkgconfig for this to work.}
 @example
-g++ -o simple `pkg-config --cflags --libs ginac` simple.cpp
+g++ -o simple simple.cpp `pkg-config --cflags --libs ginac`
 @end example
 
 This command line might expand to (for example):
 @example
-g++ -o simple -lginac -lcln simple.cpp
+g++ -o simple simple.cpp -lginac -lcln
 @end example
 
 Not only is the form using @command{pkg-config} easier to type, it will
index 4b168beaefe53566acdc33fdd72bb363b246336d..18543ecf2c49b696eb1a364d0e1275bfa40a7767 100644 (file)
@@ -1,7 +1,7 @@
 prefix=@CMAKE_INSTALL_PREFIX@
-exec_prefix=@EXEC_INSTALL_PREFIX@
-libdir=@LIB_INSTALL_DIR@
-includedir=@INCLUDE_INSTALL_DIR@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
 
 Name: GiNaC
 Description: C++ library for symbolic calculations
index dce536b1e9f755a1b91328f83d480ad4ae986e30..cacda9b59fedff97a016b3ca090c6b0d4f064711 100644 (file)
@@ -6,6 +6,6 @@ includedir=@includedir@
 Name: GiNaC
 Description: C++ library for symbolic calculations
 Version: @VERSION@
-Requires: cln >= 1.1.6
+Requires: cln >= 1.2.2
 Libs: -L${libdir} -lginac @GINACLIB_RPATH@
 Cflags: -I${includedir}
diff --git a/ginac/.gitignore b/ginac/.gitignore
new file mode 100644 (file)
index 0000000..f4c5d0d
--- /dev/null
@@ -0,0 +1,4 @@
+.libs/
+function.h
+function.cpp
+.Tpo
index 27f4db8d8a5d56c9dbeeaace4df978e651e7c288..5b0937c4089a93b3831201ae073a7838d60fe73a 100644 (file)
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 2.6)
 
 set(ginaclib_sources
     add.cpp
@@ -21,7 +20,9 @@ set(ginaclib_sources
     inifcns.cpp
     inifcns_gamma.cpp
     inifcns_nstdsums.cpp
+    inifcns_elliptic.cpp
     inifcns_trans.cpp
+    integration_kernel.cpp
     integral.cpp
     lst.cpp
     matrix.cpp
@@ -89,6 +90,7 @@ set(ginaclib_public_headers
     indexed.h 
     inifcns.h
     integral.h
+    integration_kernel.h
     lst.h
     matrix.h
     mul.h
@@ -117,6 +119,7 @@ set(ginaclib_private_headers
     utils.h
     crc32.h
     hash_seed.h
+    utils_multi_iterator.h
     parser/lexer.h
     parser/debug.h
     polynomial/gcd_euclid.h
@@ -147,12 +150,27 @@ set(ginaclib_private_headers
 )
 
 add_library(ginac ${ginaclib_sources})
-add_definitions(-DLIBEXECDIR="${LIBEXECDIR}/")
+add_library(ginac::ginac ALIAS ginac)
 set_target_properties(ginac PROPERTIES
        SOVERSION ${ginaclib_soversion}
        VERSION ${ginaclib_version})
-target_link_libraries(ginac ${CLN_LIBRARIES})
-include_directories(${CMAKE_SOURCE_DIR}/ginac)
+target_compile_definitions(ginac
+       PUBLIC $<BUILD_INTERFACE:IN_GINAC>
+       PRIVATE -DLIBEXECDIR="${LIBEXECDIR}/" HAVE_CONFIG_H
+)
+target_link_libraries(ginac PUBLIC cln::cln ${LIBDL_LIBRARIES})
+target_include_directories(ginac PUBLIC
+       $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+       $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+       $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/..>
+       $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+if (WIN32 AND CMAKE_COMPILER_IS_GNUCXX AND BUILD_SHARED_LIBS)
+       set_target_properties(ginac PROPERTIES
+               LINK_FLAGS "-Wl,--enable-auto-import -Wl,--export-all-symbols"
+       )
+endif()
 
 if (NOT BUILD_SHARED_LIBS)
        set_target_properties(ginac PROPERTIES OUTPUT_NAME "ginac")
@@ -161,18 +179,26 @@ if (NOT BUILD_SHARED_LIBS)
        set_target_properties(ginac PROPERTIES PREFIX "lib")
 endif()
 
-install(TARGETS ginac LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
-                     RUNTIME DESTINATION "${BIN_INSTALL_DIR}"
-                     ARCHIVE DESTINATION "${LIB_INSTALL_DIR}")
-install(FILES ${ginaclib_public_headers} DESTINATION "${INCLUDE_INSTALL_DIR}/ginac")
+install(TARGETS ginac
+                     EXPORT ginac-exports
+                     LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+                     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+                     ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+install(FILES ${ginaclib_public_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ginac")
+install(EXPORT ginac-exports
+       FILE ginac-targets.cmake
+       NAMESPACE ginac::
+       DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ginac
+)
 
 add_custom_command(
        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/function.h
-       COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/function.py -o ${CMAKE_CURRENT_BINARY_DIR}/function.h ${CMAKE_CURRENT_SOURCE_DIR}/function.hppy
+       COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/function.py -o ${CMAKE_CURRENT_BINARY_DIR}/function.h ${CMAKE_CURRENT_SOURCE_DIR}/function.hppy
        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/function.hppy ${CMAKE_CURRENT_SOURCE_DIR}/function.py)
 
 add_custom_command(
        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/function.cpp
-       COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/function.py -o ${CMAKE_CURRENT_BINARY_DIR}/function.cpp ${CMAKE_CURRENT_SOURCE_DIR}/function.cppy
+       COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/function.py -o ${CMAKE_CURRENT_BINARY_DIR}/function.cpp ${CMAKE_CURRENT_SOURCE_DIR}/function.cppy
        DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/function.h ${CMAKE_CURRENT_SOURCE_DIR}/function.cppy ${CMAKE_CURRENT_SOURCE_DIR}/function.py)
 
index cb76517aa89e017c198232323b4dd4ccf2e1d84f..0dc82c1503d6e253340701330eaffd4c58190a8a 100644 (file)
@@ -4,12 +4,13 @@ lib_LTLIBRARIES = libginac.la
 libginac_la_SOURCES = add.cpp archive.cpp basic.cpp clifford.cpp color.cpp \
   constant.cpp ex.cpp excompiler.cpp expair.cpp expairseq.cpp exprseq.cpp \
   fail.cpp factor.cpp fderivative.cpp function.cpp idx.cpp indexed.cpp inifcns.cpp \
-  inifcns_trans.cpp inifcns_gamma.cpp inifcns_nstdsums.cpp \
+  inifcns_trans.cpp inifcns_gamma.cpp inifcns_nstdsums.cpp inifcns_elliptic.cpp integration_kernel.cpp \
   integral.cpp lst.cpp matrix.cpp mul.cpp ncmul.cpp normal.cpp numeric.cpp \
   operators.cpp power.cpp registrar.cpp relational.cpp remember.cpp \
   pseries.cpp print.cpp symbol.cpp symmetry.cpp tensor.cpp \
   utils.cpp wildcard.cpp \
   remember.h utils.h crc32.h hash_seed.h \
+  utils_multi_iterator.h \
   parser/parse_binop_rhs.cpp \
   parser/parser.cpp \
   parser/parse_context.cpp \
@@ -64,7 +65,7 @@ ginacincludedir = $(includedir)/ginac
 ginacinclude_HEADERS = ginac.h add.h archive.h assertion.h basic.h class_info.h \
   clifford.h color.h constant.h container.h ex.h excompiler.h expair.h expairseq.h \
   exprseq.h fail.h factor.h fderivative.h flags.h function.h hash_map.h idx.h indexed.h \
-  inifcns.h integral.h lst.h matrix.h mul.h ncmul.h normal.h numeric.h operators.h \
+  inifcns.h integration_kernel.h integral.h lst.h matrix.h mul.h ncmul.h normal.h numeric.h operators.h \
   power.h print.h pseries.h ptr.h registrar.h relational.h structure.h \
   symbol.h symmetry.h tensor.h version.h wildcard.h compiler.h \
   parser/parser.h \
index 6c83e2a7028ba67b83fa9e4b2ba6e308c6bf3236..b9f47938ce2be09b897d230f23af262ea6de666a 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's sums of expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 081af04a33106f3ef8a7d0669a1e8a70686204b5..f7c64e08cf825239be4ccbe2357f8bf96a18d835 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's sums of expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -55,7 +55,7 @@ public:
        ex eval() const override;
        ex evalm() const override;
        ex series(const relational & r, int order, unsigned options = 0) const override;
-       ex normal(exmap & repl, exmap & rev_lookup) const override;
+       ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
        numeric integer_content() const override;
        ex smod(const numeric &xi) const override;
        numeric max_coefficient() const override;
index eb50e865d8df3598913ef07efc9745663e445c02..82d2b68b3fd0c799f3d343986a4b43cb50dfb5d1 100644 (file)
@@ -3,7 +3,7 @@
  *  Archiving of GiNaC expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -24,9 +24,6 @@
 #include "registrar.h"
 #include "ex.h"
 #include "lst.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
 #include "version.h"
 
 #include <iostream>
@@ -43,7 +40,7 @@ void archive::archive_ex(const ex &e, const char *name)
 
        // Add root node ID to list of archived expressions
        archived_ex ae = archived_ex(atomize(name), id);
-       exprs.push_back(ae);
+       exprs.emplace_back(ae);
 }
 
 
@@ -357,17 +354,17 @@ bool archive_node::has_same_ex_as(const archive_node &other) const
 }
 
 archive_node::archive_node_cit
-               archive_node::find_first(const std::string &name) const
-{      
+archive_node::find_first(const std::string &name) const
+{
        archive_atom name_atom = a.atomize(name);
        for (auto i=props.begin(); i!=props.end(); ++i)
                if (i->name == name_atom)
                        return i;
-       return props.end();;
+       return props.end();
 }
 
 archive_node::archive_node_cit
-               archive_node::find_last(const std::string &name) const
+archive_node::find_last(const std::string &name) const
 {
        archive_atom name_atom = a.atomize(name);
        for (auto i=props.end(); i!=props.begin();) {
@@ -378,26 +375,43 @@ archive_node::archive_node_cit
        return props.end();
 }
 
+archive_node::archive_node_cit_range
+archive_node::find_property_range(const std::string &name1, const std::string &name2) const
+{
+       archive_atom name1_atom = a.atomize(name1),
+                    name2_atom = a.atomize(name2);
+       archive_node_cit_range range = {props.end(), props.end()};
+       for (auto i=props.begin(); i!=props.end(); ++i) {
+               if (i->name == name1_atom && range.begin == props.end()) {
+                       range.begin = i;
+               }
+               if (i->name == name2_atom && range.begin != props.end()) {
+                       range.end = i + 1;
+               }
+       }
+       return range;
+}
+
 void archive_node::add_bool(const std::string &name, bool value)
 {
-       props.push_back(property(a.atomize(name), PTYPE_BOOL, value));
+       props.emplace_back(property(a.atomize(name), PTYPE_BOOL, value));
 }
 
 void archive_node::add_unsigned(const std::string &name, unsigned value)
 {
-       props.push_back(property(a.atomize(name), PTYPE_UNSIGNED, value));
+       props.emplace_back(property(a.atomize(name), PTYPE_UNSIGNED, value));
 }
 
 void archive_node::add_string(const std::string &name, const std::string &value)
 {
-       props.push_back(property(a.atomize(name), PTYPE_STRING, a.atomize(value)));
+       props.emplace_back(property(a.atomize(name), PTYPE_STRING, a.atomize(value)));
 }
 
 void archive_node::add_ex(const std::string &name, const ex &value)
 {
        // Recursively create an archive_node and add its ID to the properties of this node
        archive_node_id id = a.add_node(archive_node(a, value));
-       props.push_back(property(a.atomize(name), PTYPE_NODE, id));
+       props.emplace_back(property(a.atomize(name), PTYPE_NODE, id));
 }
 
 
@@ -455,8 +469,7 @@ bool archive_node::find_string(const std::string &name, std::string &ret, unsign
        return false;
 }
 
-void archive_node::find_ex_by_loc(archive_node_cit loc, ex &ret, lst &sym_lst)
-               const
+void archive_node::find_ex_by_loc(archive_node_cit loc, ex &ret, lst &sym_lst) const
 {
        ret = a.get_node(loc->value).unarchive(sym_lst);
 }
@@ -515,9 +528,9 @@ void archive_node::get_properties(propinfovector &v) const
                        ++a;
                }
                if (!found)
-                       v.push_back(property_info(type, name));
+                       v.emplace_back(property_info(type, name));
                i++;
-       }       
+       }
 }
 
 static synthesize_func find_factory_fcn(const std::string& name)
@@ -596,7 +609,7 @@ void archive::clear()
 /** Delete cached unarchived expressions in all archive_nodes (mainly for debugging). */
 void archive::forget()
 {
-       for_each(nodes.begin(), nodes.end(), std::mem_fun_ref(&archive_node::forget));
+       for_each(nodes.begin(), nodes.end(), std::mem_fn(&archive_node::forget));
 }
 
 /** Delete cached unarchived expressions from node (for debugging). */
index 53c45437e4e5e439c92d7de92932e418c402af98..8b7a3e4a566b971701ff35f346dcab34133b9f4c 100644 (file)
@@ -3,7 +3,7 @@
  *  Archiving of GiNaC expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -82,6 +82,9 @@ public:
                unsigned value;     /**< Stored value. */
        };
        typedef std::vector<property>::const_iterator archive_node_cit;
+       struct archive_node_cit_range {
+               archive_node_cit begin, end;
+       };
 
        archive_node(archive &ar) : a(ar), has_expression(false) {}
        archive_node(archive &ar, const ex &expr);
@@ -113,17 +116,22 @@ public:
        bool find_string(const std::string &name, std::string &ret, unsigned index = 0) const;
 
        /** Find the location in the vector of properties of the first/last
-    *  property with a given name. */
+        *  property with a given name. */
        archive_node_cit find_first(const std::string &name) const;
        archive_node_cit find_last(const std::string &name) const;
 
+       /** Find a range of locations in the vector of properties. The result
+        *  begins at the first property with name1 and ends one past the last
+        *  property with name2. */
+       archive_node_cit_range find_property_range(const std::string &name1, const std::string &name2) const;
+
        /** Retrieve property of type "ex" from node.
         *  @return "true" if property was found, "false" otherwise */
        bool find_ex(const std::string &name, ex &ret, lst &sym_lst, unsigned index = 0) const;
 
        /** Retrieve property of type "ex" from the node if it is known
-    *  that this node in fact contains such a property at the given
-    *  location. This is much more efficient than the preceding function. */
+        *  that this node in fact contains such a property at the given
+        *  location. This is much more efficient than the preceding function. */
        void find_ex_by_loc(archive_node_cit loc, ex &ret, lst &sym_lst) const;
 
        /** Retrieve property of type "ex" from node, returning the node of
@@ -271,14 +279,14 @@ public:
        /** Retrieve expression from archive by index.
         *  @param sym_lst list of pre-defined symbols
         *  @param index index of expression
-     *  @see count_expressions */
+        *  @see count_expressions */
        ex unarchive_ex(const lst &sym_lst, unsigned index = 0) const;
 
        /** Retrieve expression and its name from archive by index.
         *  @param sym_lst list of pre-defined symbols
         *  @param name receives the name of the expression
         *  @param index index of expression
-     *  @see count_expressions */
+        *  @see count_expressions */
        ex unarchive_ex(const lst &sym_lst, std::string &name, unsigned index = 0) const;
 
        /** Return number of archived expressions. */
index 6e2942c253c26383c150c10e3e161867ca65a0e1..7bac17694c477366ad64adc4fd5970e1a2092364 100644 (file)
@@ -3,7 +3,7 @@
  *  Assertion macro definition. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 1d5f695a5e25873191f4ddb490849dabc4f5228d..b5f97cda64c2e6734c5b517ee9d0a75ad2c65fa7 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's ABC. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 1a471b32337a3989ab8aea7b3954f567ed8450f5..850bc91dad771dd40baf84a81eb94bf444eeef0d 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's ABC. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -200,7 +200,7 @@ public:
        virtual ex series(const relational & r, int order, unsigned options = 0) const;
 
        // rational functions
-       virtual ex normal(exmap & repl, exmap & rev_lookup) const;
+       virtual ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const;
        virtual ex to_rational(exmap & repl) const;
        virtual ex to_polynomial(exmap & repl) const;
 
index 3f3413b005b0826e7c4eec740a2845a93097397b..1db156200b2c34ddc6bd5fe277a1eeb3efd3cbc6 100644 (file)
@@ -3,7 +3,7 @@
  *  Helper templates to provide per-class information for class hierarchies. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 860cce464acb1a81a8a308420c2bdc414e999440..2cf0facf015ab00375fa3e334fbb80573bcf1f5b 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's clifford algebra (Dirac gamma) objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -1099,7 +1099,7 @@ ex clifford_star_bar(const ex & e, bool do_bar, unsigned options)
                ev.reserve(e1.nops());
                cv.reserve(e1.nops());
                // separate clifford and non-clifford entries
-               for (int i= 0; i < e1.nops(); ++i) {
+               for (size_t i= 0; i < e1.nops(); ++i) {
                        if (is_a<clifford>(e1.op(i)) && is_a<cliffordunit>(e1.op(i).op(0)))
                                cv.push_back(e1.op(i));
                        else
@@ -1281,7 +1281,7 @@ static ex get_clifford_comp(const ex & e, const ex & c, bool root=true)
                bool found=false, same_value_found=false;
                ex dummy_ind=0;
                ev.reserve(e1.nops());
-               for (int i=0; i < e1.nops();++i) {
+               for (size_t i=0; i < e1.nops(); ++i) {
                        // look for a Clifford unit with the same metric and representation label,
                        // if found remember its index
                        if (is_a<clifford>(e1.op(i)) && ex_to<clifford>(e1.op(i)).get_representation_label() == rl
index c076d6156803efc7943a5c248c60472f4a1b6a62..0b78c49790311b5bb6c732d50615f92c79e301cb 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's clifford algebra (Dirac gamma) objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -306,7 +306,7 @@ ex remove_dirac_ONE(const ex & e, unsigned char rl = 0, unsigned options = 0);
  *  if e contains at least one, otherwise returns -1 
  *
  *  @param e Expression to be processed
- *  @ignore_ONE defines if clifford_ONE should be ignored in the search*/
+ *  @param ignore_ONE defines if clifford_ONE should be ignored in the search */
 int clifford_max_label(const ex & e, bool ignore_ONE = false);
 
 /** Calculation of the norm in the Clifford algebra. */
@@ -321,9 +321,14 @@ ex clifford_inverse(const ex & e);
  *  @param mu Index (must be of class varidx or a derived class)
  *  @param metr Metric (should be indexed, tensmetric or a derived class, or a matrix)
  *  @param rl Representation label
- *  @param e Clifford unit object
  *  @return Clifford vector with given components */
 ex lst_to_clifford(const ex & v, const ex & mu,  const ex & metr, unsigned char rl = 0);
+
+/** List or vector conversion into the Clifford vector.
+ *
+ *  @param v List or vector of coordinates
+ *  @param e Clifford unit object
+ *  @return Clifford vector with given components */
 ex lst_to_clifford(const ex & v, const ex & e);
 
 /** An inverse function to lst_to_clifford(). For given Clifford vector extracts
index f8cbca07bd369a4cc72b4fbaf3decf702bc00e05..accdccdb2b45b901996a5dd230635e6c944c7af0 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's color (SU(3) Lie algebra) objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 4dbfc3d40baa9c698ea370e73e6814c517758303..828b8c0b8d31a43eb7bba1a1d814e52593d827a6 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's color (SU(3) Lie algebra) objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 08099f57526661f258eabd819c74e617d6c35529..e9682794d05a67d3e9f0bc3007f374902b8d4a42 100644 (file)
@@ -3,7 +3,7 @@
  *  Definition of optimizing macros. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 85af0c14880a961769b6d3fd994f362002b19b62..7bdd244bac74308f4412ae1381162d084e0a41dd 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's constant types and some special constants. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 7e8916daed97773fe387a8f359158d5747671e42..55ff5e5d8556cb66c1387c67cfb5933316d9eafd 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's constant types and some special constants. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 960f07297541f481d9968f74788b3c1f20a13550..9082971011afed0acefffe706dd2d8ffd4250ee6 100644 (file)
@@ -3,7 +3,7 @@
  *  Wrapper template for making GiNaC classes out of STL containers. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -68,63 +68,6 @@ template <>
 inline void container_storage<std::vector>::reserve(std::vector<ex> & v, size_t n) { v.reserve(n); }
 
 
-/** Helper template to allow initialization of containers via an overloaded
- *  comma operator (idea stolen from Blitz++). */
-template <typename T, typename STLT>
-class container_init {
-public:
-       container_init(STLT & s) : stlt(s) {}
-
-       container_init<T, STLT> operator,(const T & x)
-       {
-               stlt.push_back(x);
-               return container_init<T, STLT>(stlt);
-       }
-
-       // The following specializations produce much tighter code than the
-       // general case above
-
-       container_init<T, STLT> operator,(int x)
-       {
-               stlt.push_back(x);
-               return container_init<T, STLT>(stlt);
-       }
-
-       container_init<T, STLT> operator,(unsigned int x)
-       {
-               stlt.push_back(x);
-               return container_init<T, STLT>(stlt);
-       }
-
-       container_init<T, STLT> operator,(long x)
-       {
-               stlt.push_back(x);
-               return container_init<T, STLT>(stlt);
-       }
-
-       container_init<T, STLT> operator,(unsigned long x)
-       {
-               stlt.push_back(x);
-               return container_init<T, STLT>(stlt);
-       }
-
-       container_init<T, STLT> operator,(double x)
-       {
-               stlt.push_back(x);
-               return container_init<T, STLT>(stlt);
-       }
-
-       container_init<T, STLT> operator,(const symbol & x)
-       {
-               stlt.push_back(T(x));
-               return container_init<T, STLT>(stlt);
-       }
-
-private:
-       container_init();
-       STLT & stlt;
-};
-
 /** Wrapper template for making GiNaC classes out of STL containers. */
 template <template <class T, class = std::allocator<T>> class C>
 class container : public basic, public container_storage<C> {
@@ -168,36 +111,6 @@ public:
                setflag(get_default_flags());
        }
 
-       explicit container(const ex & p1) attribute_deprecated;
-       container(const ex & p1, const ex & p2) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                 const ex & p9) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                 const ex & p9, const ex & p10) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                 const ex & p9, const ex & p10, const ex & p11) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                 const ex & p9, const ex & p10, const ex & p11, const ex & p12) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                 const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                 const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                 const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15) attribute_deprecated;
-       container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                 const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15, const ex & p16) attribute_deprecated;
-
-       // First step of initialization of container with a comma-separated
-       // sequence of expressions. Subsequent steps are handled by
-       // container_init<>::operator,().
-       container_init<ex, STLT> operator=(const ex & x) attribute_deprecated;
-
        // functions overriding virtual functions from base classes
 public:
        bool info(unsigned inf) const override { return inherited::info(inf); }
@@ -212,14 +125,12 @@ public:
                inherited::read_archive(n, sym_lst);
                setflag(get_default_flags());
 
-               archive_node::archive_node_cit first = n.find_first("seq");
-               archive_node::archive_node_cit last = n.find_last("seq");
-               ++last;
-               this->reserve(this->seq, last - first);
-               for (archive_node::archive_node_cit i=first; i<last; ++i) {
+               auto range =  n.find_property_range("seq", "seq");
+               this->reserve(this->seq, range.end - range.begin);
+               for (archive_node::archive_node_cit i=range.begin; i<range.end; ++i) {
                        ex e;
                        n.find_ex_by_loc(i, e, sym_lst);
-                       this->seq.push_back(e);
+                       this->seq.emplace_back(e);
                }
        }
 
@@ -345,85 +256,6 @@ container<C>::container()
        setflag(get_default_flags());
 }
 
-/** Deprecatd constructors (prefer initializer list) */
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1)
-  : container_storage<C>(1, p1) { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2)
-  : container_storage<C>{p1, p2} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3)
-  : container_storage<C>{p1, p2, p3} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4)
-  : container_storage<C>{p1, p2, p3, p4} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5)
-  : container_storage<C>{p1, p2, p3, p4, p5} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                        const ex & p9)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                        const ex & p9, const ex & p10)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                        const ex & p9, const ex & p10, const ex & p11)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                        const ex & p9, const ex & p10, const ex & p11, const ex & p12)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                        const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                        const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                        const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15} { setflag(get_default_flags()); }
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
-                        const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15, const ex & p16)
-  : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container_init<ex, typename container_storage<C>::STLT> container<C>::operator=(const ex & x)
-{
-       this->seq.push_back(x);
-       return container_init<ex, typename container_storage<C>::STLT>(this->seq);
-}
-
 template <template <class T, class = std::allocator<T>> class C>
 void container<C>::do_print(const print_context & c, unsigned level) const
 {
index 73a3ba79239e7b8b34ba111416110c6b66f8430d..a052b7223a745d65898cdf8eb7dd7687b70df32b 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's light-weight expression handles. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -70,6 +70,8 @@ void ex::dbgprinttree() const
        bp->dbgprinttree();
 }
 
+/** Expand an expression.
+ *  @param options  see GiNaC::expand_options */
 ex ex::expand(unsigned options) const
 {
        if (options == 0 && (bp->flags & status_flags::expanded)) // The "expanded" flag only covers the standard options; someone might want to re-expand with different options
@@ -530,7 +532,25 @@ basic & ex::construct_from_ulong(unsigned long i)
                return dynallocate<numeric>(i);
        }
 }
-       
+
+basic & ex::construct_from_longlong(long long i)
+{
+       if (i >= -12 && i <= 12) {
+               return construct_from_int(static_cast<int>(i));
+       } else {
+               return dynallocate<numeric>(i);
+       }
+}
+
+basic & ex::construct_from_ulonglong(unsigned long long i)
+{
+       if (i <= 12) {
+               return construct_from_uint(static_cast<unsigned>(i));
+       } else {
+               return dynallocate<numeric>(i);
+       }
+}
+
 basic & ex::construct_from_double(double d)
 {
        return dynallocate<numeric>(d);
index 606cd9d8e87ffc188441670fe1ff929ffadb02b1..5381a38aad85fa2213bfd28ffadf6cacdf496a69 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's light-weight expression handles. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -43,7 +43,7 @@ namespace GiNaC {
  *  of this class in every object file that makes use of our flyweights in
  *  order to guarantee proper initialization.  Hence we put it into this
  *  file which is included by every relevant file anyways.  This is modeled
- *  after section 27.4.2.1.6 of the C++ standard, where cout and friends are
+ *  after section [ios::Init] of the C++ standard, where cout and friends are
  *  set up.
  *
  *  @see utils.cpp */
@@ -87,6 +87,8 @@ public:
        ex(unsigned int i);
        ex(long i);
        ex(unsigned long i);
+       ex(long long i);
+       ex(unsigned long long i);
        ex(double const d);
 
        /** Construct ex from string and a list of symbols. The input grammar is
@@ -132,8 +134,8 @@ public:
        // operand access
        size_t nops() const { return bp->nops(); }
        ex op(size_t i) const { return bp->op(i); }
-       ex operator[](const ex & index) const { return (*bp)[index]; }
-       ex operator[](size_t i) const { return (*bp)[i]; }
+       ex operator[](const ex & index) const { return (const_cast<const basic&>(*bp))[index]; }
+       ex operator[](size_t i) const { return (const_cast<const basic&>(*bp))[i]; }
        ex & let_op(size_t i);
        ex & operator[](const ex & index);
        ex & operator[](size_t i);
@@ -236,6 +238,8 @@ private:
        static basic & construct_from_uint(unsigned int i);
        static basic & construct_from_long(long i);
        static basic & construct_from_ulong(unsigned long i);
+       static basic & construct_from_longlong(long long i);
+       static basic & construct_from_ulonglong(unsigned long long i);
        static basic & construct_from_double(double d);
        static ptr<basic> construct_from_string_and_lst(const std::string &s, const ex &l);
        void makewriteable();
@@ -290,6 +294,18 @@ ex::ex(unsigned long i) : bp(construct_from_ulong(i))
        GINAC_ASSERT(bp->flags & status_flags::dynallocated);
 }
 
+inline
+ex::ex(long long i) : bp(construct_from_longlong(i))
+{
+       GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+}
+
+inline
+ex::ex(unsigned long long i) : bp(construct_from_ulonglong(i))
+{
+       GINAC_ASSERT(bp->flags & status_flags::dynallocated);
+}
+
 inline
 ex::ex(double const d) : bp(construct_from_double(d))
 {
@@ -351,12 +367,17 @@ bool ex::is_equal(const ex & other) const
 
 // Iterators
 
-class const_iterator : public std::iterator<std::random_access_iterator_tag, ex, ptrdiff_t, const ex *, const ex &> {
+class const_iterator {
        friend class ex;
        friend class const_preorder_iterator;
        friend class const_postorder_iterator;
-
 public:
+       using iterator_category = std::random_access_iterator_tag;
+       using value_type = ex;
+       using difference_type = ptrdiff_t;
+       using pointer = const ex *;
+       using reference = const ex &;
+
        const_iterator() noexcept {}
 
 private:
@@ -497,8 +518,13 @@ struct _iter_rep {
 
 } // namespace internal
 
-class const_preorder_iterator : public std::iterator<std::forward_iterator_tag, ex, ptrdiff_t, const ex *, const ex &> {
+class const_preorder_iterator {
 public:
+       using iterator_category = std::forward_iterator_tag;
+       using value_type = ex;
+       using difference_type = ptrdiff_t;
+       using pointer = const ex *;
+       using reference = const ex &;
        const_preorder_iterator() noexcept {}
 
        const_preorder_iterator(const ex &e, size_t n)
@@ -561,8 +587,13 @@ private:
        }
 };
 
-class const_postorder_iterator : public std::iterator<std::forward_iterator_tag, ex, ptrdiff_t, const ex *, const ex &> {
+class const_postorder_iterator {
 public:
+       using iterator_category = std::forward_iterator_tag;
+       using value_type = ex;
+       using difference_type = ptrdiff_t;
+       using pointer = const ex *;
+       using reference = const ex &;
        const_postorder_iterator() noexcept {}
 
        const_postorder_iterator(const ex &e, size_t n)
@@ -962,6 +993,26 @@ inline void swap(GiNaC::ex &a, GiNaC::ex &b)
        a.swap(b);
 }
 
+/** Specialization of std::hash() for ex objects. */
+template<>
+struct hash<GiNaC::ex>
+{
+       std::size_t operator()(const GiNaC::ex & e) const noexcept
+       {
+               return e.gethash();
+       }
+};
+
+/** Specialization of std::equal_to() for ex objects. */
+template<>
+struct equal_to<GiNaC::ex>
+{
+       bool operator()(const GiNaC::ex &e1, const GiNaC::ex &e2) const noexcept
+       {
+               return e1.is_equal(e2);
+       }
+};
+
 } // namespace std
 
 #endif // ndef GINAC_EX_H
index c54c4659c297d0f242b816c328315134ba1e68ab..513c19a7058a164da7b097f44326fe0d5de4bd0f 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 0baf9ffd47ea8eb2d3465c68ca759408d581690b..a2ad9b9c42e55de83159b126ee1999abf582a4de 100644 (file)
@@ -4,7 +4,7 @@
  *  fast numerical integration. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -65,7 +65,8 @@ void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::stri
  * C code equivalent in double precision. The function pointer has type FUNCP_2P.
  *
  * @param expr Expression to be compiled
- * @param sym Symbol from the expression to become the function parameter
+ * @param sym1 Symbol from the expression to become the first function parameter
+ * @param sym2 Symbol from the expression to become the second function parameter
  * @param fp Returned function pointer
  * @param filename Name of the intermediate source code and so-file. If
  * supplied, these intermediate files will not be deleted
@@ -76,8 +77,8 @@ void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P
  * Takes an expression and produces a function pointer to the compiled and linked
  * C code equivalent in double precision. The function pointer has type FUNCP_CUBA.
  *
- * @param expr Expression to be compiled
- * @param sym Symbol from the expression to become the function parameter
+ * @param exprs List of expression to be compiled
+ * @param syms Symbols from the expression to become the function parameters
  * @param fp Returned function pointer
  * @param filename Name of the intermediate source code and so-file. If
  * supplied, these intermediate files will not be deleted
index a7e4fab2f5055f8c3092dc72dbc0bc4271bc4fc8..d30dda882ec304ccb750c24acf54109e35f5b621 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of expression pairs (building blocks of expairseq). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 94b3065a954b6750d3148f6289b71b8e8b8c133d..452a6f2c672f502eae3483cf12aff7dfc6726b52 100644 (file)
@@ -3,7 +3,7 @@
  *  Definition of expression pairs (building blocks of expairseq). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index a1361532fc9994c7c920560f3893bca469aea286..cef087153c5fb61facc66ce1e95df40e7e1187d5 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of sequences of expression pairs. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -112,17 +112,15 @@ expairseq::expairseq(epvector && vp, const ex &oc, bool do_index_renaming)
 void expairseq::read_archive(const archive_node &n, lst &sym_lst) 
 {
        inherited::read_archive(n, sym_lst);
-       auto first = n.find_first("rest");
-       auto last = n.find_last("coeff");
-       ++last;
-       seq.reserve((last-first)/2);
+       auto range = n.find_property_range("rest", "coeff");
+       seq.reserve((range.end-range.begin)/2);
 
-       for (auto loc = first; loc < last;) {
+       for (auto loc = range.begin; loc < range.end;) {
                ex rest;
                ex coeff;
                n.find_ex_by_loc(loc++, rest, sym_lst);
                n.find_ex_by_loc(loc++, coeff, sym_lst);
-               seq.push_back(expair(rest, coeff));
+               seq.emplace_back(expair(rest, coeff));
        }
 
        n.find_ex("overall_coeff", overall_coeff, sym_lst);
index 1b4191796550c0f565322a5873bb3ad3c8af4cdb..7554369be230375aab4a95fae9644001df3e581e 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to sequences of expression pairs. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index cb3720701f1a5a65a7a62f601c912f89ba20f94a..fb02be1aefa5874fce96ea0463381d171cac09d8 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's exprseq. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 99eeef1e72725d9d15e645fbc120e0c67d9a6cbd..a0381ec9c4758030917ed1755535676aae0ff405 100644 (file)
@@ -3,7 +3,7 @@
  *  Definition of GiNaC's exprseq. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -31,6 +31,11 @@ namespace GiNaC {
 
 typedef container<std::vector> exprseq;
 
+/** Declaration of container::reg_info for exprseq. */
+#ifndef _MSC_VER  // workaround error C2766: explicit specialization; 'reg_info' has already been defined
+template<> registered_class_info exprseq::reg_info;
+#endif
+
 // defined in exprseq.cpp
 template<> bool exprseq::info(unsigned inf) const;
 
index 2b77d1b0110f3e327216a11a20510b901a6b93ee..efe438eae8c59e658cd7553d2867aa42c71556b3 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -65,6 +65,7 @@
 #include "normal.h"
 #include "add.h"
 
+#include <type_traits>
 #include <algorithm>
 #include <limits>
 #include <list>
@@ -80,6 +81,9 @@ using namespace cln;
 
 namespace GiNaC {
 
+// anonymous namespace to hide all utility functions
+namespace {
+
 #ifdef DEBUGFACTOR
 #define DCOUT(str) cout << #str << endl
 #define DCOUTVAR(var) cout << #var << ": " << var << endl
@@ -133,9 +137,6 @@ ostream& operator<<(ostream& o, const vector<vector<cl_MI>>& v)
 #define DCOUT2(str,var)
 #endif // def DEBUGFACTOR
 
-// anonymous namespace to hide all utility functions
-namespace {
-
 ////////////////////////////////////////////////////////////////////////////////
 // modular univariate polynomial code
 
@@ -143,7 +144,8 @@ typedef std::vector<cln::cl_MI> umodpoly;
 typedef std::vector<cln::cl_I> upoly;
 typedef vector<umodpoly> upvec;
 
-// COPY FROM UPOLY.HPP
+
+// COPY FROM UPOLY.H
 
 // CHANGED size_t -> int !!!
 template<typename T> static int degree(const T& p)
@@ -156,6 +158,11 @@ template<typename T> static typename T::value_type lcoeff(const T& p)
        return p[p.size() - 1];
 }
 
+/** Make the polynomial unit normal (having unit normal leading coefficient).
+ *
+ *  @param[in, out] a  polynomial to make unit normal
+ *  @return            true if polynomial a was already unit normal, false otherwise
+ */
 static bool normalize_in_field(umodpoly& a)
 {
        if (a.size() == 0)
@@ -170,61 +177,22 @@ static bool normalize_in_field(umodpoly& a)
        return false;
 }
 
+/** Remove leading zero coefficients from polynomial.
+ *
+ *  @param[in, out] p     polynomial from which the zero leading coefficients will be removed
+ *  @param[in]      hint  assume all coefficients of order â‰¥ hint are zero
+ */
 template<typename T> static void
 canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
 {
-       if (p.empty())
-               return;
+       std::size_t i = min(p.size(), hint);
 
-       std::size_t i = p.size() - 1;
-       // Be fast if the polynomial is already canonicalized
-       if (!zerop(p[i]))
-               return;
-
-       if (hint < p.size())
-               i = hint;
+       while ( i-- && zerop(p[i]) ) { }
 
-       bool is_zero = false;
-       do {
-               if (!zerop(p[i])) {
-                       ++i;
-                       break;
-               }
-               if (i == 0) {
-                       is_zero = true;
-                       break;
-               }
-               --i;
-       } while (true);
-
-       if (is_zero) {
-               p.clear();
-               return;
-       }
-
-       p.erase(p.begin() + i, p.end());
+       p.erase(p.begin() + i + 1, p.end());
 }
 
-// END COPY FROM UPOLY.HPP
-
-static void expt_pos(umodpoly& a, unsigned int q)
-{
-       if ( a.empty() ) return;
-       cl_MI zero = a[0].ring()->zero(); 
-       int deg = degree(a);
-       a.resize(degree(a)*q+1, zero);
-       for ( int i=deg; i>0; --i ) {
-               a[i*q] = a[i];
-               a[i] = zero;
-       }
-}
-
-template<bool COND, typename T = void> struct enable_if
-{
-       typedef T type;
-};
-
-template<typename T> struct enable_if<false, T> { /* empty */ };
+// END COPY FROM UPOLY.H
 
 template<typename T> struct uvar_poly_p
 {
@@ -487,12 +455,12 @@ static umodpoly umodpoly_to_umodpoly(const umodpoly& a, const cl_modint_ring& R,
        return e;
 }
 
-/** Divides all coefficients of the polynomial a by the integer x.
+/** Divides all coefficients of the polynomial a by the positive integer x.
  *  All coefficients are supposed to be divisible by x. If they are not, the
- *  the<cl_I> cast will raise an exception.
+ *  division will raise an exception.
  *
  *  @param[in,out] a  polynomial of which the coefficients will be reduced by x
- *  @param[in]     x  integer that divides the coefficients
+ *  @param[in]     x  positive integer that divides the coefficients
  */
 static void reduce_coeff(umodpoly& a, const cl_I& x)
 {
@@ -502,7 +470,7 @@ static void reduce_coeff(umodpoly& a, const cl_I& x)
        for (auto & i : a) {
                // cln cannot perform this division in the modular field
                cl_I c = R->retract(i);
-               i = cl_MI(R, the<cl_I>(c / x));
+               i = cl_MI(R, exquopos(c, x));
        }
 }
 
@@ -532,7 +500,7 @@ static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r)
        } while ( k-- );
 
        fill(r.begin()+n, r.end(), a[0].ring()->zero());
-       canonicalize(r);
+       canonicalize(r, n);
 }
 
 /** Calculates quotient of a/b.
@@ -643,7 +611,6 @@ static void deriv(const umodpoly& a, umodpoly& d)
 
 static bool unequal_one(const umodpoly& a)
 {
-       if ( a.empty() ) return true;
        return ( a.size() != 1 || a[0] != a[0].ring()->one() );
 }
 
@@ -669,6 +636,26 @@ static bool squarefree(const umodpoly& a)
        return equal_one(c);
 }
 
+/** Computes w^q mod a.
+ *  Uses theorem 2.1 from A.K.Lenstra's PhD thesis; see exercise 8.13 in [GCL].
+ *
+ *  @param[in]  w  polynomial
+ *  @param[in]  a  modulus polynomial
+ *  @param[in]  q  common modulus of w and a
+ *  @param[out] r  result
+ */
+static void expt_pos_Q(const umodpoly& w, const umodpoly& a, unsigned int q, umodpoly& r)
+{
+       if ( w.empty() ) return;
+       cl_MI zero = w[0].ring()->zero();
+       int deg = degree(w);
+       umodpoly buf(deg*q+1, zero);
+       for ( size_t i=0; i<=deg; ++i ) {
+               buf[i*q] = w[i];
+       }
+       rem(buf, a, r);
+}
+
 // END modular univariate polynomial code
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -814,6 +801,8 @@ ostream& operator<<(ostream& o, const modular_matrix& m)
 ////////////////////////////////////////////////////////////////////////////////
 
 /** Calculates the Q matrix for a polynomial. Used by Berlekamp's algorithm.
+ *
+ *  The implementation follows algorithm 8.5 of [GCL].
  *
  *  @param[in]  a_  modular polynomial
  *  @param[out] Q   Q matrix
@@ -892,7 +881,7 @@ static void nullspace(modular_matrix& M, vector<mvec>& basis)
 
 /** Berlekamp's modular factorization.
  *  
- *  The implementation follows the algorithm in chapter 8 of [GCL].
+ *  The implementation follows algorithm 8.4 of [GCL].
  *
  *  @param[in]  a    modular polynomial
  *  @param[out] upv  vector containing modular factors. if upv was not empty the
@@ -965,9 +954,9 @@ static void berlekamp(const umodpoly& a, upvec& upv)
 
 /** Calculates a^(1/prime).
  *  
- *  @param[in] a      polynomial
- *  @param[in] prime  prime number -> exponent 1/prime
- *  @param[in] ap     resulting polynomial
+ *  @param[in]  a      polynomial
+ *  @param[in]  prime  prime number -> exponent 1/prime
+ *  @param[out] ap     resulting polynomial
  */
 static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap)
 {
@@ -1033,7 +1022,7 @@ static void modsqrfree(const umodpoly& a, upvec& factors, vector<int>& mult)
 
 /** Distinct degree factorization (DDF).
  *  
- *  The implementation follows the algorithm in chapter 8 of [GCL].
+ *  The implementation follows algorithm 8.8 of [GCL].
  *
  *  @param[in]  a_         modular polynomial
  *  @param[out] degrees    vector containing the degrees of the factors of the
@@ -1050,23 +1039,17 @@ static void distinct_degree_factor(const umodpoly& a_, vector<int>& degrees, upv
        int nhalf = degree(a)/2;
 
        int i = 1;
-       umodpoly w(2);
-       w[0] = R->zero();
-       w[1] = R->one();
+       umodpoly w = {R->zero(), R->one()};
        umodpoly x = w;
 
        while ( i <= nhalf ) {
-               expt_pos(w, q);
                umodpoly buf;
-               rem(w, a, buf);
+               expt_pos_Q(w, a, q, buf);
                w = buf;
-               umodpoly wx = w - x;
-               gcd(a, wx, buf);
+               gcd(a, w - x, buf);
                if ( unequal_one(buf) ) {
                        degrees.push_back(i);
                        ddfactors.push_back(buf);
-               }
-               if ( unequal_one(buf) ) {
                        umodpoly buf2;
                        div(a, buf, buf2);
                        a = buf2;
@@ -1193,43 +1176,35 @@ static upoly replace_lc(const upoly& poly, const cl_I& lc)
        return r;
 }
 
-/** Calculates the bound for the modulus.
- *  See [Mig].
+/** Calculates bound for the product of absolute values (modulus) of the roots.
+ *  Uses Landau's inequality, see [Mig].
  */
-static inline cl_I calc_bound(const ex& a, const ex& x, int maxdeg)
+static inline cl_I calc_bound(const ex& a, const ex& x)
 {
-       cl_I maxcoeff = 0;
-       cl_R coeff = 0;
+       cl_R radicand = 0;
        for ( int i=a.degree(x); i>=a.ldegree(x); --i ) {
                cl_I aa = abs(the<cl_I>(ex_to<numeric>(a.coeff(x, i)).to_cl_N()));
-               if ( aa > maxcoeff ) maxcoeff = aa;
-               coeff = coeff + square(aa);
+               radicand = radicand + square(aa);
        }
-       cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff)));
-       cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg));
-       return ( B > maxcoeff ) ? B : maxcoeff;
+       return ceiling1(the<cl_R>(cln::sqrt(radicand)));
 }
 
-/** Calculates the bound for the modulus.
- *  See [Mig].
+/** Calculates bound for the product of absolute values (modulus) of the roots.
+ *  Uses Landau's inequality, see [Mig].
  */
-static inline cl_I calc_bound(const upoly& a, int maxdeg)
+static inline cl_I calc_bound(const upoly& a)
 {
-       cl_I maxcoeff = 0;
-       cl_R coeff = 0;
+       cl_R radicand = 0;
        for ( int i=degree(a); i>=0; --i ) {
                cl_I aa = abs(a[i]);
-               if ( aa > maxcoeff ) maxcoeff = aa;
-               coeff = coeff + square(aa);
+               radicand = radicand + square(aa);
        }
-       cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff)));
-       cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg));
-       return ( B > maxcoeff ) ? B : maxcoeff;
+       return ceiling1(the<cl_R>(cln::sqrt(radicand)));
 }
 
 /** Hensel lifting as used by factor_univariate().
  *
- *  The implementation follows the algorithm in chapter 6 of [GCL].
+ *  The implementation follows algorithm 6.1 of [GCL].
  *
  *  @param[in]  a_   primitive univariate polynomials
  *  @param[in]  p    prime number that does not divide lcoeff(a)
@@ -1246,7 +1221,7 @@ static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_,
 
        // calc bound B
        int maxdeg = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
-       cl_I maxmodulus = 2*calc_bound(a, maxdeg);
+       cl_I maxmodulus = ash(calc_bound(a), maxdeg+1);  // = 2 * calc_bound(a) * 2^maxdeg
 
        // step 1
        cl_I alpha = lcoeff(a);
@@ -1314,42 +1289,36 @@ static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_,
        }
 }
 
-/** Returns a new prime number.
+/** Returns a new small prime number.
  *
- *  @param[in] p  prime number
- *  @return       next prime number after p
+ *  @param[in] n  an integer
+ *  @return       smallest prime greater than n
  */
-static unsigned int next_prime(unsigned int p)
-{
-       static vector<unsigned int> primes;
-       if (primes.empty()) {
-               primes = {3, 5, 7};
-       }
-       if ( p >= primes.back() ) {
-               unsigned int candidate = primes.back() + 2;
-               while ( true ) {
-                       size_t n = primes.size()/2;
-                       for ( size_t i=0; i<n; ++i ) {
-                               if (candidate % primes[i])
-                                       continue;
-                               candidate += 2;
-                               i=-1;
-                       }
-                       primes.push_back(candidate);
-                       if (candidate > p)
+static unsigned int next_prime(unsigned int n)
+{
+       static vector<unsigned int> primes = {2, 3, 5, 7};
+       unsigned int candidate = primes.back();
+       while (primes.back() <= n) {
+               candidate += 2;
+               bool is_prime = true;
+               for (size_t i=1; primes[i]*primes[i]<=candidate; ++i) {
+                       if (candidate % primes[i] == 0) {
+                               is_prime = false;
                                break;
+                       }
                }
-               return candidate;
+               if (is_prime)
+                       primes.push_back(candidate);
        }
        for (auto & it : primes) {
-               if ( it > p ) {
+               if ( it > n ) {
                        return it;
                }
        }
        throw logic_error("next_prime: should not reach this point!");
 }
 
-/** Manages the splitting a vector of of modular factors into two partitions.
+/** Manages the splitting of a vector of modular factors into two partitions.
  */
 class factor_partition
 {
@@ -1491,6 +1460,9 @@ static ex factor_univariate(const ex& poly, const ex& x, unsigned int& prime)
        poly.unitcontprim(x, unit, cont, prim_ex);
        upoly prim;
        upoly_from_ex(prim, prim_ex, x);
+       if (prim_ex.is_equal(1)) {
+               return poly;
+       }
 
        // determine proper prime and minimize number of modular factors
        prime = 3;
@@ -1659,7 +1631,7 @@ static vector<ex> multivar_diophant(const vector<ex>& a_, const ex& x, const ex&
  *  with deg(s_i) < deg(a_i)
  *  and with given b_1 = a_1 * ... * a_{i-1} * a_{i+1} * ... * a_r
  *
- *  The implementation follows the algorithm in chapter 6 of [GCL].
+ *  The implementation follows algorithm 6.3 of [GCL].
  *
  *  @param[in]  a   vector of modular univariate polynomials
  *  @param[in]  x   symbol
@@ -1714,7 +1686,7 @@ static void change_modulus(const cl_modint_ring& R, umodpoly& a)
  *
  *  Solves  s*a + t*b == 1 mod p^k  given a,b.
  *
- *  The implementation follows the algorithm in chapter 6 of [GCL].
+ *  The implementation follows algorithm 6.3 of [GCL].
  *
  *  @param[in]  a   polynomial
  *  @param[in]  b   polynomial
@@ -1773,7 +1745,7 @@ static void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned
  *    s_1*b_1 + ... + s_r*b_r == x^m mod p^k
  *  with given b_1 = a_1 * ... * a_{i-1} * a_{i+1} * ... * a_r
  *
- *  The implementation follows the algorithm in chapter 6 of [GCL].
+ *  The implementation follows algorithm 6.3 of [GCL].
  *
  *  @param a  vector with univariate polynomials mod p^k
  *  @param x  symbol
@@ -1857,7 +1829,7 @@ static ex make_modular(const ex& e, const cl_modint_ring& R)
  *    s_1*b_1 + ... + s_r*b_r == c mod <I^(d+1),p^k>
  *  with given b_1 = a_1 * ... * a_{i-1} * a_{i+1} * ... * a_r
  *
- *  The implementation follows the algorithm in chapter 6 of [GCL].
+ *  The implementation follows algorithm 6.2 of [GCL].
  *
  *  @param a_  vector of multivariate factors mod p^k
  *  @param x   symbol (equiv. x_1 in [GCL])
@@ -1967,7 +1939,7 @@ static vector<ex> multivar_diophant(const vector<ex>& a_, const ex& x, const ex&
 }
 
 /** Multivariate Hensel lifting.
- *  The implementation follows the algorithm in chapter 6 of [GCL].
+ *  The implementation follows algorithm 6.4 of [GCL].
  *  Since we don't have a data type for modular multivariate polynomials, the
  *  respective operations are done in a GiNaC::ex and the function
  *  make_modular() is then called to make the coefficient modular p^l.
@@ -2073,62 +2045,63 @@ static ex hensel_multivar(const ex& a, const ex& x, const vector<EvalPoint>& I,
        }
 }
 
-/** Takes a factorized expression and puts the factors in a lst. The exponents
+/** Takes a factorized expression and puts the factors in a vector. The exponents
  *  of the factors are discarded, e.g. 7*x^2*(y+1)^4 --> {7,x,y+1}. The first
- *  element of the list is always the numeric coefficient.
+ *  element of the result is always the numeric coefficient.
  */
-static ex put_factors_into_lst(const ex& e)
+static exvector put_factors_into_vec(const ex& e)
 {
-       lst result;
+       exvector result;
        if ( is_a<numeric>(e) ) {
-               result.append(e);
+               result.push_back(e);
                return result;
        }
        if ( is_a<power>(e) ) {
-               result.append(1);
-               result.append(e.op(0));
+               result.push_back(1);
+               result.push_back(e.op(0));
                return result;
        }
        if ( is_a<symbol>(e) || is_a<add>(e) ) {
                ex icont(e.integer_content());
-               result.append(icont);
-               result.append(e/icont);
+               result.push_back(icont);
+               result.push_back(e/icont);
                return result;
        }
        if ( is_a<mul>(e) ) {
                ex nfac = 1;
+               result.push_back(nfac);
                for ( size_t i=0; i<e.nops(); ++i ) {
                        ex op = e.op(i);
                        if ( is_a<numeric>(op) ) {
                                nfac = op;
                        }
                        if ( is_a<power>(op) ) {
-                               result.append(op.op(0));
+                               result.push_back(op.op(0));
                        }
                        if ( is_a<symbol>(op) || is_a<add>(op) ) {
-                               result.append(op);
+                               result.push_back(op);
                        }
                }
-               result.prepend(nfac);
+               result[0] = nfac;
                return result;
        }
-       throw runtime_error("put_factors_into_lst: bad term.");
+       throw runtime_error("put_factors_into_vec: bad term.");
 }
 
 /** Checks a set of numbers for whether each number has a unique prime factor.
  *
- *  @param[in]  f  list of numbers to check
+ *  @param[in]  f  numbers to check
  *  @return        true: if number set is bad, false: if set is okay (has unique
  *                 prime factors)
  */
-static bool checkdivisors(const lst& f)
+static bool checkdivisors(const exvector& f)
 {
-       const int k = f.nops();
+       const int k = f.size();
        numeric q, r;
        vector<numeric> d(k);
-       d[0] = ex_to<numeric>(abs(f.op(0)));
+       d[0] = ex_to<numeric>(abs(f[0]));
        for ( int i=1; i<k; ++i ) {
-               q = ex_to<numeric>(abs(f.op(i)));
+               q = ex_to<numeric>(abs(f[i]));
                for ( int j=i-1; j>=0; --j ) {
                        r = d[j];
                        do {
@@ -2153,25 +2126,24 @@ static bool checkdivisors(const lst& f)
  *
  *  @param[in]     u        multivariate polynomial to be factored
  *  @param[in]     vn       leading coefficient of u in x (x==first symbol in syms)
- *  @param[in]     syms     set of symbols that appear in u
- *  @param[in]     f        lst containing the factors of the leading coefficient vn
+ *  @param[in]     x        first symbol that appears in u
+ *  @param[in]     syms_wox remaining symbols that appear in u
+ *  @param[in]     f        vector containing the factors of the leading coefficient vn
  *  @param[in,out] modulus  integer modulus for random number generation (i.e. |a_i| < modulus)
  *  @param[out]    u0       returns the evaluated (univariate) polynomial
  *  @param[out]    a        returns the valid evaluation points. must have initial size equal
  *                          number of symbols-1 before calling generate_set
  */
-static void generate_set(const ex& u, const ex& vn, const exset& syms, const lst& f,
+static void generate_set(const ex& u, const ex& vn, const ex& x, const exset& syms_wox, const exvector& f,
                          numeric& modulus, ex& u0, vector<numeric>& a)
 {
-       const ex& x = *syms.begin();
        while ( true ) {
                ++modulus;
                // generate a set of integers ...
                u0 = u;
                ex vna = vn;
                ex vnatry;
-               exset::const_iterator s = syms.begin();
-               ++s;
+               auto s = syms_wox.begin();
                for ( size_t i=0; i<a.size(); ++i ) {
                        do {
                                a[i] = mod(numeric(rand()), 2*modulus) - modulus;
@@ -2189,14 +2161,13 @@ static void generate_set(const ex& u, const ex& vn, const exset& syms, const lst
                }
                if ( !is_a<numeric>(vn) ) {
                        // ... and for which the evaluated factors have each an unique prime factor
-                       lst fnum = f;
-                       fnum.let_op(0) = fnum.op(0) * u0.content(x);
-                       for ( size_t i=1; i<fnum.nops(); ++i ) {
-                               if ( !is_a<numeric>(fnum.op(i)) ) {
-                                       s = syms.begin();
-                                       ++s;
+                       exvector fnum = f;
+                       fnum[0] = fnum[0] * u0.content(x);
+                       for ( size_t i=1; i<fnum.size(); ++i ) {
+                               if ( !is_a<numeric>(fnum[i]) ) {
+                                       s = syms_wox.begin();
                                        for ( size_t j=0; j<a.size(); ++j, ++s ) {
-                                               fnum.let_op(i) = fnum.op(i).subs(*s == a[j]);
+                                               fnum[i] = fnum[i].subs(*s == a[j]);
                                        }
                                }
                        }
@@ -2212,72 +2183,42 @@ static void generate_set(const ex& u, const ex& vn, const exset& syms, const lst
 // forward declaration
 static ex factor_sqrfree(const ex& poly);
 
-/** Multivariate factorization.
- *  
- *  The implementation is based on the algorithm described in [Wan].
- *  An evaluation homomorphism (a set of integers) is determined that fulfills
- *  certain criteria. The evaluated polynomial is univariate and is factorized
- *  by factor_univariate(). The main work then is to find the correct leading
- *  coefficients of the univariate factors. They have to correspond to the
- *  factors of the (multivariate) leading coefficient of the input polynomial
- *  (as defined for a specific variable x). After that the Hensel lifting can be
- *  performed.
- *
- *  @param[in] poly  expanded, square free polynomial
- *  @param[in] syms  contains the symbols in the polynomial
- *  @return          factorized polynomial
+/** Used by factor_multivariate().
  */
-static ex factor_multivariate(const ex& poly, const exset& syms)
-{
-       exset::const_iterator s;
-       const ex& x = *syms.begin();
-
-       // make polynomial primitive
-       ex unit, cont, pp;
-       poly.unitcontprim(x, unit, cont, pp);
-       if ( !is_a<numeric>(cont) ) {
-               return factor_sqrfree(cont) * factor_sqrfree(pp);
-       }
-
-       // factor leading coefficient
-       ex vn = pp.collect(x).lcoeff(x);
-       ex vnlst;
-       if ( is_a<numeric>(vn) ) {
-               vnlst = lst{vn};
-       }
-       else {
-               ex vnfactors = factor(vn);
-               vnlst = put_factors_into_lst(vnfactors);
-       }
-
-       const unsigned int maxtrials = 3;
-       numeric modulus = (vnlst.nops() > 3) ? vnlst.nops() : 3;
-       vector<numeric> a(syms.size()-1, 0);
-
-       // try now to factorize until we are successful
-       while ( true ) {
+struct factorization_ctx {
+       const ex poly, x;         // polynomial, first symbol x...
+       const exset syms_wox;     // ...remaining symbols w/o x
+       ex unit, cont, pp;        // unit * cont * pp == poly
+       ex vn; exvector vnlst;    // leading coeff, factors of leading coeff
+       numeric modulus;          // incremented each time we try
+       /** returns factors or empty if it did not succeed */
+       ex try_next_evaluation_homomorphism()
+       {
+               constexpr unsigned maxtrials = 3;
+               vector<numeric> a(syms_wox.size(), 0);
 
                unsigned int trialcount = 0;
                unsigned int prime;
                int factor_count = 0;
                int min_factor_count = -1;
                ex u, delta;
-               ex ufac, ufaclst;
+               ex ufac;
+               exvector ufaclst;
 
                // try several evaluation points to reduce the number of factors
                while ( trialcount < maxtrials ) {
 
                        // generate a set of valid evaluation points
-                       generate_set(pp, vn, syms, ex_to<lst>(vnlst), modulus, u, a);
+                       generate_set(pp, vn, x, syms_wox, vnlst, modulus, u, a);
 
                        ufac = factor_univariate(u, x, prime);
-                       ufaclst = put_factors_into_lst(ufac);
-                       factor_count = ufaclst.nops()-1;
-                       delta = ufaclst.op(0);
+                       ufaclst = put_factors_into_vec(ufac);
+                       factor_count = ufaclst.size()-1;
+                       delta = ufaclst[0];
 
                        if ( factor_count <= 1 ) {
                                // irreducible
-                               return poly;
+                               return lst{pp};
                        }
                        if ( min_factor_count < 0 ) {
                                // first time here
@@ -2298,19 +2239,18 @@ static ex factor_multivariate(const ex& poly, const exset& syms)
                vector<ex> C(factor_count);
                if ( is_a<numeric>(vn) ) {
                        // easy case
-                       for ( size_t i=1; i<ufaclst.nops(); ++i ) {
-                               C[i-1] = ufaclst.op(i).lcoeff(x);
+                       for ( size_t i=1; i<ufaclst.size(); ++i ) {
+                               C[i-1] = ufaclst[i].lcoeff(x);
                        }
                } else {
                        // difficult case.
                        // we use the property of the ftilde having a unique prime factor.
                        // details can be found in [Wan].
                        // calculate ftilde
-                       vector<numeric> ftilde(vnlst.nops()-1);
+                       vector<numeric> ftilde(vnlst.size()-1);
                        for ( size_t i=0; i<ftilde.size(); ++i ) {
-                               ex ft = vnlst.op(i+1);
-                               s = syms.begin();
-                               ++s;
+                               ex ft = vnlst[i+1];
+                               auto s = syms_wox.begin();
                                for ( size_t j=0; j<a.size(); ++j ) {
                                        ft = ft.subs(*s == a[j]);
                                        ++s;
@@ -2322,39 +2262,41 @@ static ex factor_multivariate(const ex& poly, const exset& syms)
                        vector<ex> D(factor_count, 1);
                        if ( delta == 1 ) {
                                for ( int i=0; i<factor_count; ++i ) {
-                                       numeric prefac = ex_to<numeric>(ufaclst.op(i+1).lcoeff(x));
+                                       numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(x));
                                        for ( int j=ftilde.size()-1; j>=0; --j ) {
                                                int count = 0;
-                                               while ( irem(prefac, ftilde[j]) == 0 ) {
-                                                       prefac = iquo(prefac, ftilde[j]);
+                                               numeric q;
+                                               while ( irem(prefac, ftilde[j], q) == 0 ) {
+                                                       prefac = q;
                                                        ++count;
                                                }
                                                if ( count ) {
                                                        used_flag[j] = true;
-                                                       D[i] = D[i] * pow(vnlst.op(j+1), count);
+                                                       D[i] = D[i] * pow(vnlst[j+1], count);
                                                }
                                        }
                                        C[i] = D[i] * prefac;
                                }
                        } else {
                                for ( int i=0; i<factor_count; ++i ) {
-                                       numeric prefac = ex_to<numeric>(ufaclst.op(i+1).lcoeff(x));
+                                       numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(x));
                                        for ( int j=ftilde.size()-1; j>=0; --j ) {
                                                int count = 0;
-                                               while ( irem(prefac, ftilde[j]) == 0 ) {
-                                                       prefac = iquo(prefac, ftilde[j]);
+                                               numeric q;
+                                               while ( irem(prefac, ftilde[j], q) == 0 ) {
+                                                       prefac = q;
                                                        ++count;
                                                }
                                                while ( irem(ex_to<numeric>(delta)*prefac, ftilde[j]) == 0 ) {
                                                        numeric g = gcd(prefac, ex_to<numeric>(ftilde[j]));
                                                        prefac = iquo(prefac, g);
                                                        delta = delta / (ftilde[j]/g);
-                                                       ufaclst.let_op(i+1) = ufaclst.op(i+1) * (ftilde[j]/g);
+                                                       ufaclst[i+1] = ufaclst[i+1] * (ftilde[j]/g);
                                                        ++count;
                                                }
                                                if ( count ) {
                                                        used_flag[j] = true;
-                                                       D[i] = D[i] * pow(vnlst.op(j+1), count);
+                                                       D[i] = D[i] * pow(vnlst[j+1], count);
                                                }
                                        }
                                        C[i] = D[i] * prefac;
@@ -2369,60 +2311,114 @@ static ex factor_multivariate(const ex& poly, const exset& syms)
                                }
                        }
                        if ( some_factor_unused ) {
-                               continue;
+                               return lst{};  // next try
                        }
                }
-               
+
                // multiply the remaining content of the univariate polynomial into the
                // first factor
                if ( delta != 1 ) {
                        C[0] = C[0] * delta;
-                       ufaclst.let_op(1) = ufaclst.op(1) * delta;
+                       ufaclst[1] = ufaclst[1] * delta;
                }
 
                // set up evaluation points
-               EvalPoint ep;
                vector<EvalPoint> epv;
-               s = syms.begin();
-               ++s;
+               auto s = syms_wox.begin();
                for ( size_t i=0; i<a.size(); ++i ) {
-                       ep.x = *s++;
-                       ep.evalpoint = a[i].to_int();
-                       epv.push_back(ep);
+                       epv.emplace_back(EvalPoint{*s++, a[i].to_int()});
                }
 
                // calc bound p^l
                int maxdeg = 0;
                for ( int i=1; i<=factor_count; ++i ) {
-                       if ( ufaclst.op(i).degree(x) > maxdeg ) {
+                       if ( ufaclst[i].degree(x) > maxdeg ) {
                                maxdeg = ufaclst[i].degree(x);
                        }
                }
-               cl_I B = 2*calc_bound(u, x, maxdeg);
+               cl_I B = ash(calc_bound(u, x), maxdeg+1);  // = 2 * calc_bound(u,x) * 2^maxdeg
                cl_I l = 1;
                cl_I pl = prime;
                while ( pl < B ) {
                        l = l + 1;
                        pl = pl * prime;
                }
-               
+
                // set up modular factors (mod p^l)
-               cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
-               upvec modfactors(ufaclst.nops()-1);
-               for ( size_t i=1; i<ufaclst.nops(); ++i ) {
-                       umodpoly_from_ex(modfactors[i-1], ufaclst.op(i), x, R);
+               cl_modint_ring R = find_modint_ring(pl);
+               upvec modfactors(ufaclst.size()-1);
+               for ( size_t i=1; i<ufaclst.size(); ++i ) {
+                       umodpoly_from_ex(modfactors[i-1], ufaclst[i], x, R);
                }
 
                // try Hensel lifting
-               ex res = hensel_multivar(pp, x, epv, prime, l, modfactors, C);
+               return hensel_multivar(pp, x, epv, prime, l, modfactors, C);
+       }
+};
+
+/** Multivariate factorization.
+ *
+ *  The implementation is based on the algorithm described in [Wan].
+ *  An evaluation homomorphism (a set of integers) is determined that fulfills
+ *  certain criteria. The evaluated polynomial is univariate and is factorized
+ *  by factor_univariate(). The main work then is to find the correct leading
+ *  coefficients of the univariate factors. They have to correspond to the
+ *  factors of the (multivariate) leading coefficient of the input polynomial
+ *  (as defined for a specific variable x). After that the Hensel lifting can be
+ *  performed. This is done in round-robin for each x in syms until success.
+ *
+ *  @param[in] poly  expanded, square free polynomial
+ *  @param[in] syms  contains the symbols in the polynomial
+ *  @return          factorized polynomial
+ */
+static ex factor_multivariate(const ex& poly, const exset& syms)
+{
+       // set up one factorization context for each symbol
+       vector<factorization_ctx> ctx_in_x;
+       for (auto x : syms) {
+               exset syms_wox;  // remaining syms w/o x
+               copy_if(syms.begin(), syms.end(),
+                       inserter(syms_wox, syms_wox.end()), [x](const ex& y){ return y != x; });
+
+               factorization_ctx ctx{poly, x, syms_wox};
+
+               // make polynomial primitive
+               poly.unitcontprim(x, ctx.unit, ctx.cont, ctx.pp);
+               if ( !is_a<numeric>(ctx.cont) ) {
+                       // content is a polynomial in one or more of remaining syms, let's start over
+                       return ctx.unit * factor_sqrfree(ctx.cont) * factor_sqrfree(ctx.pp);
+               }
+
+               // find factors of leading coefficient
+               ctx.vn = ctx.pp.collect(x).lcoeff(x);
+               ctx.vnlst = put_factors_into_vec(factor(ctx.vn));
+
+               ctx.modulus = (ctx.vnlst.size() > 3) ? ctx.vnlst.size() : numeric(3);
+
+               ctx_in_x.push_back(ctx);
+       }
+
+       // try an evaluation homomorphism for each context in round-robin
+       auto ctx = ctx_in_x.begin();
+       while ( true ) {
+
+               ex res = ctx->try_next_evaluation_homomorphism();
+
                if ( res != lst{} ) {
-                       ex result = cont * unit;
+                       // found the factors
+                       ex result = ctx->cont * ctx->unit;
                        for ( size_t i=0; i<res.nops(); ++i ) {
-                               result *= res.op(i).content(x) * res.op(i).unit(x);
-                               result *= res.op(i).primpart(x);
+                               ex unit, cont, pp;
+                               res.op(i).unitcontprim(ctx->x, unit, cont, pp);
+                               result *= unit * cont * pp;
                        }
                        return result;
                }
+
+               // switch context for next symbol
+               if (++ctx == ctx_in_x.end()) {
+                       ctx = ctx_in_x.begin();
+               }
        }
 }
 
@@ -2455,9 +2451,9 @@ static ex factor_sqrfree(const ex& poly)
        if ( findsymbols.syms.size() == 1 ) {
                // univariate case
                const ex& x = *(findsymbols.syms.begin());
-               if ( poly.ldegree(x) > 0 ) {
+               int ld = poly.ldegree(x);
+               if ( ld > 0 ) {
                        // pull out direct factors
-                       int ld = poly.ldegree(x);
                        ex res = factor_univariate(expand(poly/pow(x, ld)), x);
                        return res * pow(x,ld);
                } else {
@@ -2590,7 +2586,3 @@ ex factor(const ex& poly, unsigned options)
 }
 
 } // namespace GiNaC
-
-#ifdef DEBUGFACTOR
-#include "test.h"
-#endif
index 945310fbe4a6bc66a24a863ef25960c6f2577593..ccdb595e637aa95c9ea419973794fcead4b0382d 100644 (file)
@@ -3,7 +3,7 @@
  *  Polynomial factorization. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@ class ex;
  *  functions or polynomials inside function arguments.
  *
  *  @param[in] poly    expression to factorize
- *  @param[in] option  options to influence the factorization
+ *  @param[in] options see GiNaC::factor_options
  *  @return            factorized expression
  */
 extern ex factor(const ex& poly, unsigned options = 0);
index a03bbfed19f59a51371e2204aba190cfbfc2f3f9..ad65225aa7d8fd1ba6f322ba379706f4e9341cca 100644 (file)
@@ -4,7 +4,7 @@
  *  somewhat obsolete (most of this can be replaced by exceptions). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 5b3264610c085d36d71821cf5fcfd45d938a2543..4afee2f215a9424f1bd9dda330b547b343ab4aa7 100644 (file)
@@ -4,7 +4,7 @@
  *  somewhat obsolete (most of this can be replaced by exceptions). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 3ed3c90a811a7a36648cbd83db1651c0cd030821..1bc31063b2421205c6d7a62f3c08117ba22dee56 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of abstract derivatives of functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index f0e2a56fbe697cb7be1ec1adcf610aaa2851594e..e213e8dd28f0e3b3abe5c25bf238437557f07498 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to abstract derivatives of functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 02a114b34837131a3300dec2b750ecb5a67ced9f..b1425b2f2ee74f88bbdcb4e4f1c762d3c3f41600 100644 (file)
@@ -3,7 +3,7 @@
  *  Collection of all flags used through the GiNaC framework. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 3b2ee05b770df5c7782e6d0e9e096626c1b81136..115845e156942a924d51794f3c8b0ad6a5db006d 100644 (file)
@@ -7,7 +7,7 @@
  *  Please do not modify it directly, edit function.cppy instead!
  *  function.py options: maxargs=@maxargs@
  *
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -259,18 +259,20 @@ function::function(unsigned ser, exvector && v)
 void function::read_archive(const archive_node& n, lst& sym_lst)
 {
        inherited::read_archive(n, sym_lst);
-       // Find serial number by function name
+       // Find serial number by function name and number of parameters
+       unsigned np = seq.size();
        std::string s;
        if (n.find_string("name", s)) {
                unsigned int ser = 0;
                for (auto & it : registered_functions()) {
-                       if (s == it.name) {
+                       if (s == it.name && np == registered_functions()[ser].nparams) {
                                serial = ser;
                                return;
                        }
                        ++ser;
                }
-               throw (std::runtime_error("unknown function '" + s + "' in archive"));
+               throw (std::runtime_error("unknown function '" + s +
+                                         "' with " + std::to_string(np) + " parameters in archive"));
        } else
                throw (std::runtime_error("unnamed function in archive"));
 }
@@ -435,7 +437,7 @@ ex function::evalf() const
        }
        current_serial = serial;
        if (opt.evalf_use_exvector_args)
-               return ((evalf_funcp_exvector)(opt.evalf_f))(seq);
+               return ((evalf_funcp_exvector)(opt.evalf_f))(eseq);
        switch (opt.nparams) {
                // the following lines have been generated for max. @maxargs@ parameters
 +++ for N in range(1, maxargs + 1):
index 29c32a2dad01702cbc31c0baec246df0c95d9907..aa1d6ceef611a3423736afb66295252ffa24ecbf 100644 (file)
@@ -6,7 +6,7 @@
  *  This file was generated automatically from function.hppy.
  *  Please do not modify it directly, edit function.hppy instead!
  *
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
old mode 100755 (executable)
new mode 100644 (file)
index 63012a2..f7dc7d4
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+
 # encoding: utf-8
 
 maxargs = 14
index fca196ff0a330da4c9855fa5dc0ecd0f75859f91..9840b001d79d611aee155803ccc1ea5d03d7a1f4 100644 (file)
@@ -3,7 +3,7 @@
  *  This include file includes all other public GiNaC headers. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -68,6 +68,8 @@
 
 #include "factor.h"
 
+#include "integration_kernel.h"
+
 #include "excompiler.h"
 
 #ifndef IN_GINAC
index fb37d862cc752106baa0913e91a8f6fb7da30569..ce77509e9d6f0b1dedde27becbbfdca1dd806ff1 100644 (file)
@@ -3,7 +3,7 @@
  *  Replacement for map<> using hash tables. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #ifndef GINAC_HASH_MAP_H
 #define GINAC_HASH_MAP_H
 
-#include <algorithm>
-#include <functional>
-#include <iterator>
-#include <list>
-#include <utility>
+#include <unordered_map>
 
 namespace GiNaC {
 
-/*
- *  "Hashmap Light" - buckets only contain one value, quadratic probing,
- *  grows automatically
- */
-
-namespace internal {
-
-// List of prime numbers shamelessly stolen from GCC STL
-enum { num_primes = 29 };
-
-static const unsigned long prime_list[num_primes] =
-{
-       31ul,        53ul,         97ul,         193ul,       389ul,
-       769ul,       1543ul,       3079ul,       6151ul,      12289ul,
-       24593ul,     49157ul,      98317ul,      196613ul,    393241ul,
-       786433ul,    1572869ul,    3145739ul,    6291469ul,   12582917ul,
-       25165843ul,  50331653ul,   100663319ul,  201326611ul, 402653189ul,
-       805306457ul, 1610612741ul, 3221225473ul, 4294967291ul
-};
-
-inline unsigned long next_prime(unsigned long n)
-{
-       const unsigned long *first = prime_list;
-       const unsigned long *last = prime_list + num_primes;
-       const unsigned long *pos = std::lower_bound(first, last, n);
-       return pos == last ? *(last - 1) : *pos;
-}
-
-} // namespace internal
-
-
-// Define default arguments
-template <typename T, template <class> class A = std::allocator>
-class exhashmap;
-
-
-/** Pair Associative Container with 'ex' objects as keys, that is implemented
- *  with a hash table and can be used as a replacement for map<> in many cases.
- *
- *  Differences to map<>:
- *   - no lower_bound()/upper_bound()
- *   - no reverse iterators, no rbegin()/rend()
- *   - no operator<()
- *   - comparison functor is hardcoded to ex_is_less
- *   - bucket_count() returns the number of buckets allocated in the hash table
- *   - insert() and erase() invalidate all iterators
- *   - average complexity of find() is constant time, worst case is O(n) */
-template <typename T, template <class> class A>
-class exhashmap {
-public:
-       static const unsigned min_num_buckets = 31; // must be prime
-
-       // Standard types
-       typedef ex key_type;
-       typedef T mapped_type;
-       typedef std::pair<key_type, T> value_type;
-       typedef ex_is_less key_compare;
-       typedef ex_is_equal key_equal;
-       typedef value_type & reference;
-       typedef const value_type & const_reference;
-       typedef value_type * pointer;
-       typedef const value_type * const_pointer;
-
-protected:
-       // Private types
-       enum bucket_state {
-               EMPTY,  ///< bucket empty (never used)
-               USED,   ///< bucket in use
-               ERASED  ///< bucket empty (element deleted), but may be part of a search chain
-       };
-       typedef std::pair<bucket_state, value_type> Bucket;
-
-public:
-       // More standard types
-       typedef A<Bucket> allocator_type;
-
-protected:
-       // More private types
-       typedef std::vector<Bucket, allocator_type> Table;
-
-       typedef typename Table::iterator table_iterator;
-       typedef typename Table::const_iterator table_const_iterator;
-
-public:
-       // Iterators
-       template <typename Pointer, typename Reference, class TableIterator>
-       class exhashmap_iterator : public std::iterator<std::forward_iterator_tag, value_type, typename Table::difference_type, Pointer, Reference> {
-       protected:
-               friend class exhashmap;
-
-       public:
-               exhashmap_iterator() {}
-               exhashmap_iterator(TableIterator t, TableIterator te)
-                : it(t), table_end(te) {}
-
-               // Allow iterator to const_iterator conversion
-               template <typename P, typename R, class TI>
-               exhashmap_iterator(const exhashmap_iterator<P, R, TI> &other)
-                : it(other.get_it_()), table_end(other.get_table_end_()) {}
-
-               typename exhashmap_iterator::reference operator*() const
-               {
-                       return it->second;
-               }
-
-               typename exhashmap_iterator::pointer operator->() const
-               {
-                       return &(it->second);
-               }
-
-               exhashmap_iterator &operator++()
-               {
-                       increment();
-                       return *this;
-               }
-
-               exhashmap_iterator operator++(int)
-               {
-                       exhashmap_iterator tmp = *this;
-                       increment();
-                       return tmp;
-               }
-
-               template <typename P, typename R, class TI>
-               bool operator==(const exhashmap_iterator<P, R, TI> &other) const
-               {
-                       return it == other.get_it_();
-               }
-
-               template <typename P, typename R, class TI>
-               bool operator!=(const exhashmap_iterator<P, R, TI> &other) const
-               {
-                       return it != other.get_it_();
-               }
-
-               // Private access function
-               TableIterator get_it_() const { return it; }
-               TableIterator get_table_end_() const { return table_end; }
-
-       protected:
-               TableIterator it;        ///< Pointer to current bucket
-               TableIterator table_end; ///< Pointer to one-past-last bucket
-
-               void increment()
-               {
-                       if (it != table_end)
-                               ++it;
-
-                       // Skip empty and erased buckets
-                       while (it != table_end && it->first != USED)
-                               ++it;
-               }
-       };
-
-       typedef exhashmap_iterator<value_type*, value_type&, table_iterator> iterator;
-       typedef exhashmap_iterator<const value_type*, const value_type&, table_const_iterator> const_iterator;
-
-       // More standard types
-       typedef typename Table::size_type size_type;
-       typedef typename Table::difference_type difference_type;
-
-       class value_compare : private key_compare {
-               friend class exhashmap;
-       public:
-               bool operator()(const value_type &lhs, const value_type &rhs) const
-               {
-                       return key_compare::operator()(lhs.first, rhs.first);
-               }
-
-               bool operator()(const key_type &lhs, const value_type &rhs) const
-               {
-                       return key_compare::operator()(lhs, rhs.first);
-               }
-
-               bool operator()(const value_type &lhs, const key_type &rhs) const
-               {
-                       return key_compare::operator()(lhs.first, rhs);
-               }
-       };
-
-protected:
-       // Private data
-       size_type num_entries; ///< Number of values stored in container (cached for faster operation of size())
-       size_type num_buckets; ///< Number of buckets (= hashtab.size())
-       Table hashtab;         ///< Vector of buckets, each bucket is kept sorted
-
-       /** Return index of key in hash table. */
-       static size_type hash_index(const key_type &x, size_type nbuckets)
-       {
-               return x.gethash() % nbuckets;
-       }
-
-       static table_iterator find_bucket(const key_type &x, table_iterator tab, size_type nbuckets);
-       static table_const_iterator find_bucket(const key_type &x, table_const_iterator tab, size_type nbuckets);
-       static table_iterator find_bucket_for_insertion(const key_type &x, table_iterator tab, size_type nbuckets);
-
-       /** Return pointer to bucket corresponding to key (or first empty bucket). */
-       table_iterator find_bucket(const key_type &x)
-       {
-               return find_bucket(x, hashtab.begin(), num_buckets);
-       }
-
-       /** Return pointer to bucket corresponding to key (or first empty bucket). */
-       table_const_iterator find_bucket(const key_type &x) const
-       {
-               return find_bucket(x, hashtab.begin(), num_buckets);
-       }
-
-       /** Return pointer to bucket corresponding to key (or first empty or erased bucket). */
-       table_iterator find_bucket_for_insertion(const key_type &x)
-       {
-               return find_bucket_for_insertion(x, hashtab.begin(), num_buckets);
-       }
-
-       /** Return number of entries above which the table will grow. */
-       size_type hwm() const
-       {
-               // Try to keep at least 25% of the buckets free
-               return num_buckets - (num_buckets >> 2);
-       }
-
-       void grow();
-
-public:
-       // 23.3.1.1 Construct/copy/destroy
-       exhashmap()
-        : num_entries(0), num_buckets(min_num_buckets), hashtab(num_buckets, std::make_pair(EMPTY, std::make_pair(0, mapped_type()))) {}
-
-       explicit exhashmap(size_type nbuckets)
-        : num_entries(0), num_buckets(internal::next_prime(nbuckets)), hashtab(num_buckets, std::make_pair(EMPTY, std::make_pair(0, mapped_type()))) {}
-
-       template <class InputIterator>
-       exhashmap(InputIterator first, InputIterator last)
-        : num_entries(0), num_buckets(min_num_buckets), hashtab(num_buckets, std::make_pair(EMPTY, std::make_pair(0, mapped_type())))
-       {
-               insert(first, last);
-       }
-
-       exhashmap &operator=(const exhashmap &other)
-       {
-               exhashmap(other).swap(*this);
-               return *this;
-       }
-
-       // Iterators
-       iterator begin()
-       {
-               // Find first used bucket
-               table_iterator bucket = hashtab.begin();
-               while (bucket != hashtab.end() && bucket->first != USED)
-                       ++bucket;
-               return iterator(bucket, hashtab.end());
-       }
-
-       const_iterator begin() const
-       {
-               // Find first used bucket
-               table_const_iterator bucket = hashtab.begin();
-               while (bucket != hashtab.end() && bucket->first != USED)
-                       ++bucket;
-               return const_iterator(bucket, hashtab.end());
-       }
-
-       iterator end()
-       {
-               return iterator(hashtab.end(), hashtab.end());
-       }
-
-       const_iterator end() const
-       {
-               return const_iterator(hashtab.end(), hashtab.end());
-       }
-
-       // Capacity
-       bool empty() const
-       {
-               return num_entries == 0;
-       }
-
-       size_type size() const
-       {
-               return num_entries;
-       }
-
-       size_type max_size() const
-       {
-               return hashtab.max_size();
-       }
-
-       size_type bucket_count() const
-       {
-               return num_buckets;
-       }
-
-       // 23.3.1.2 Element access
-       T &operator[](const key_type &x)
-       {
-               return insert(value_type(x, mapped_type())).first->second;
-       }
-
-       // Modifiers
-       std::pair<iterator, bool> insert(const value_type &x);
-
-       iterator insert(iterator pos, const value_type &x)
-       {
-               return insert(x).first;
-       }
-
-       template <class InputIterator>
-       void insert(InputIterator first, InputIterator last)
-       {
-               for (; first != last; ++first)
-                       insert(*first);
-       }
-
-       void erase(iterator position)
-       {
-               table_iterator bucket = position.get_it_();
-               bucket->first = ERASED;
-               bucket->second.first = 0;
-               --num_entries;
-       }
-
-       size_type erase(const key_type &x);
-
-       void swap(exhashmap &other)
-       {
-               hashtab.swap(other.hashtab);
-               std::swap(num_buckets, other.num_buckets);
-               std::swap(num_entries, other.num_entries);
-       }
-
-       void clear();
-
-       // Observers
-       key_compare key_comp() const
-       {
-               return key_compare();
-       }
-
-       value_compare value_comp() const
-       {
-               return value_compare();
-       }
-
-       // 23.3.1.3 Map operations
-       iterator find(const key_type &x);
-       const_iterator find(const key_type &x) const;
-
-       size_type count(const key_type &x) const
-       {
-               return find(x) == end() ? 0 : 1;
-       }
-
-       std::pair<iterator, iterator> equal_range(const key_type &x)
-       {
-               iterator i = find(x);
-               if (i == end())
-                       return std::make_pair(i, i);
-               else {
-                       iterator j = ++i;
-                       return std::make_pair(i, j);
-               }
-       }
-
-       std::pair<const_iterator, const_iterator> equal_range(const key_type &x) const
-       {
-               const_iterator i = find(x);
-               if (i == end())
-                       return std::make_pair(i, i);
-               else {
-                       const_iterator j = ++i;
-                       return std::make_pair(i, j);
-               }
-       }
-
-       friend bool operator==(const exhashmap &lhs, const exhashmap &rhs)
-       {
-               if (lhs.num_entries != rhs.num_entries || lhs.num_buckets != rhs.num_buckets)
-                       return false;
-
-               // We can't compare the tables directly as the elements may be
-               // in different order due to the collision handling. We therefore
-               // look up each value from the lhs map in the rhs map separately.
-               for (const_iterator itl = lhs.begin(); itl != lhs.end(); ++itl) {
-                       const_iterator itr = rhs.find(itl->first);
-                       if (itr == rhs.end())
-                               return false;
-                       if (itl->second != itr->second)
-                               return false;
-               }
-               return true;
-       }
-
-       friend bool operator!=(const exhashmap &lhs, const exhashmap &rhs)
-       {
-               return !(lhs == rhs);
-       }
-
-#if 0
-       void dump() const
-       {
-               std::clog << "num_entries = " << num_entries << std::endl;
-               std::clog << "num_buckets = " << num_buckets << std::endl;
-               size_type t = 0;
-               for (table_const_iterator it = hashtab.begin(); it != hashtab.end(); ++it, ++t) {
-                       std::clog << " bucket " << t << ": ";
-                       std::clog << (it->first == EMPTY ? "free" : (it->first == USED ? "used" : "erased")) << ", " << it->second.first << " -> " << it->second.second << std::endl;
-               }
-       }
-#endif
-};
-
-/** Return pointer to bucket corresponding to key (or first empty bucket). */
-template <typename T, template <class> class A>
-inline typename exhashmap<T, A>::table_iterator exhashmap<T, A>::find_bucket(const key_type &x, table_iterator tab, size_type nbuckets)
-{
-       // Quadratic probing
-       size_type h = hash_index(x, nbuckets);
-       size_type d = 1;
-       table_iterator it = tab + h;
-       while (it->first != EMPTY && !(it->first == USED && key_equal()(it->second.first, x))) {
-               h = (h + d) % nbuckets;
-               d += 2;
-               it = tab + h;
-       }
-       return it;
-}
-
-/** Return pointer to bucket corresponding to key (or first empty bucket). */
-template <typename T, template <class> class A>
-inline typename exhashmap<T, A>::table_const_iterator exhashmap<T, A>::find_bucket(const key_type &x, table_const_iterator tab, size_type nbuckets)
-{
-       // Quadratic probing
-       size_type h = hash_index(x, nbuckets);
-       size_type d = 1;
-       table_const_iterator it = tab + h;
-       while (it->first != EMPTY && !(it->first == USED && key_equal()(it->second.first, x))) {
-               h = (h + d) % nbuckets;
-               d += 2;
-               it = tab + h;
-       }
-       return it;
-}
-
-/** Return pointer to bucket corresponding to key (or first empty or erased bucket). */
-template <typename T, template <class> class A>
-inline typename exhashmap<T, A>::table_iterator exhashmap<T, A>::find_bucket_for_insertion(const key_type &x, table_iterator tab, size_type nbuckets)
-{
-       // Quadratic probing
-       size_type h = hash_index(x, nbuckets);
-       size_type d = 1;
-       table_iterator it = tab + h;
-       while (it->first != EMPTY && !key_equal()(it->second.first, x)) {
-               h = (h + d) % nbuckets;
-               d += 2;
-               it = tab + h;
-       }
-       return it;
-}
-
-/** Grow hash table */
-template <typename T, template <class> class A>
-void exhashmap<T, A>::grow()
-{
-       // Allocate new empty hash table
-       size_type new_num_buckets = internal::next_prime(num_buckets + 1);
-       Table new_hashtab;
-       new_hashtab.resize(new_num_buckets);
-       for (table_iterator it = new_hashtab.begin(); it != new_hashtab.end(); ++it)
-               it->first = EMPTY;
-
-       // Re-insert all elements into new table
-       for (table_const_iterator it = hashtab.begin(); it != hashtab.end(); ++it) {
-               if (it->first == USED) {
-                       table_iterator bucket = find_bucket(it->second.first, new_hashtab.begin(), new_num_buckets);
-                       *bucket = *it;
-               }
-       }
-
-       // Swap with the old table
-       hashtab.swap(new_hashtab);
-       num_buckets = new_num_buckets;
-}
-
-template <typename T, template <class> class A>
-std::pair<typename exhashmap<T, A>::iterator, bool> exhashmap<T, A>::insert(const value_type &x)
-{
-       table_iterator bucket = find_bucket_for_insertion(x.first);
-       if (bucket->first == USED) {
-               // Value already in map
-               return std::make_pair(iterator(bucket, hashtab.end()), false);
-       } else {
-               // Insert new value
-               bucket->first = USED;
-               bucket->second = x;
-               ++num_entries;
-               if (num_entries >= hwm()) {
-                       grow();
-                       bucket = find_bucket(x.first);
-               }
-               return std::make_pair(iterator(bucket, hashtab.end()), true);
-       }
-}
-
-template <typename T, template <class> class A>
-typename exhashmap<T, A>::size_type exhashmap<T, A>::erase(const key_type &x)
-{
-       iterator i = find(x);
-       if (i != end()) {
-               erase(i);
-               return 1;
-       } else
-               return 0;
-}
-
-template <typename T, template <class> class A>
-typename exhashmap<T, A>::iterator exhashmap<T, A>::find(const key_type &x)
-{
-       table_iterator bucket = find_bucket(x);
-       if (bucket->first == USED)
-               return iterator(bucket, hashtab.end());
-       else
-               return end();
-}
-
-template <typename T, template <class> class A>
-typename exhashmap<T, A>::const_iterator exhashmap<T, A>::find(const key_type &x) const
-{
-       table_const_iterator bucket = find_bucket(x);
-       if (bucket->first == USED)
-               return const_iterator(bucket, hashtab.end());
-       else
-               return end();
-}
-
-template <typename T, template <class> class A>
-void exhashmap<T, A>::clear()
-{
-       for (table_iterator i = hashtab.begin(); i != hashtab.end(); ++i) {
-               i->first = EMPTY;
-               i->second.first = 0;
-               i->second.second = mapped_type();
-       }
-       num_entries = 0;
-}
+template <typename T,
+         class Hash = std::hash<ex>,
+         class KeyEqual = std::equal_to<ex>,
+         class Allocator = std::allocator<std::pair<const ex, T>>>
+using exhashmap = std::unordered_map<ex, T, Hash, KeyEqual, Allocator>;
 
 } // namespace GiNaC
 
-
-// Specializations of Standard Library algorithms
-namespace std {
-
-/** Specialization of std::swap() for exhashmap. */
-template <typename T, template <class> class A>
-inline void swap(GiNaC::exhashmap<T, A> &lhs, GiNaC::exhashmap<T, A> &rhs)
-{
-       lhs.swap(rhs);
-}
-
-} // namespace std
-
 #endif // ndef GINAC_HASH_MAP_H
index e50fac4062a0e771a8d711962e69203e8f00f9e0..479481f1ba3393cb63da395d5a8627193296059d 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's indices. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e38bf20baaf587dac2b430d82fbc6ac4bce48f69..beb137d12d967f4c940825ec8ace48d392b210ef 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's indices. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -41,8 +41,7 @@ public:
        /** Construct index with given value and dimension.
         *
         *  @param v Value of index (numeric or symbolic)
-        *  @param dim Dimension of index space (numeric or symbolic)
-        *  @return newly constructed index */
+        *  @param dim Dimension of index space (numeric or symbolic) */
        explicit idx(const ex & v, const ex & dim);
 
        // functions overriding virtual functions from base classes
@@ -119,8 +118,7 @@ public:
         *
         *  @param v Value of index (numeric or symbolic)
         *  @param dim Dimension of index space (numeric or symbolic)
-        *  @param covariant Make covariant index (default is contravariant)
-        *  @return newly constructed index */
+        *  @param covariant Make covariant index (default is contravariant) */
        varidx(const ex & v, const ex & dim, bool covariant = false);
 
        // functions overriding virtual functions from base classes
@@ -169,8 +167,7 @@ public:
         *  @param v Value of index (numeric or symbolic)
         *  @param dim Dimension of index space (numeric or symbolic)
         *  @param covariant Make covariant index (default is contravariant)
-        *  @param dotted Make covariant dotted (default is undotted)
-        *  @return newly constructed index */
+        *  @param dotted Make covariant dotted (default is undotted) */
        spinidx(const ex & v, const ex & dim = 2, bool covariant = false, bool dotted = false);
 
        // functions overriding virtual functions from base classes
index 5becdda2858a940edc6fe61bc15e349b9ae45588..1c3b51467438e08479775b49c36230cf259ecf76 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's indexed expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 21fe777dd73b6b0b507d85332be9a4253cee0961..c66bcea6ff17deae35edf233834780fdc1d95bd6 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's indexed expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -48,23 +48,20 @@ class indexed : public exprseq
 public:
        /** Construct indexed object with no index.
         *
-        *  @param b Base expression
-        *  @return newly constructed indexed object */
+        *  @param b Base expression */
        indexed(const ex & b);
 
        /** Construct indexed object with one index. The index must be of class idx.
         *
         *  @param b Base expression
-        *  @param i1 The index
-        *  @return newly constructed indexed object */
+        *  @param i1 The index */
        indexed(const ex & b, const ex & i1);
 
        /** Construct indexed object with two indices. The indices must be of class idx.
         *
         *  @param b Base expression
         *  @param i1 First index
-        *  @param i2 Second index
-        *  @return newly constructed indexed object */
+        *  @param i2 Second index */
        indexed(const ex & b, const ex & i1, const ex & i2);
 
        /** Construct indexed object with three indices. The indices must be of class idx.
@@ -72,8 +69,7 @@ public:
         *  @param b Base expression
         *  @param i1 First index
         *  @param i2 Second index
-        *  @param i3 Third index
-        *  @return newly constructed indexed object */
+        *  @param i3 Third index */
        indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3);
 
        /** Construct indexed object with four indices. The indices must be of class idx.
@@ -82,8 +78,7 @@ public:
         *  @param i1 First index
         *  @param i2 Second index
         *  @param i3 Third index
-        *  @param i4 Fourth index
-        *  @return newly constructed indexed object */
+        *  @param i4 Fourth index */
        indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3, const ex & i4);
 
        /** Construct indexed object with two indices and a specified symmetry. The
@@ -92,8 +87,7 @@ public:
         *  @param b Base expression
         *  @param symm Symmetry of indices
         *  @param i1 First index
-        *  @param i2 Second index
-        *  @return newly constructed indexed object */
+        *  @param i2 Second index */
        indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2);
 
        /** Construct indexed object with three indices and a specified symmetry.
@@ -103,8 +97,7 @@ public:
         *  @param symm Symmetry of indices
         *  @param i1 First index
         *  @param i2 Second index
-        *  @param i3 Third index
-        *  @return newly constructed indexed object */
+        *  @param i3 Third index */
        indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2, const ex & i3);
 
        /** Construct indexed object with four indices and a specified symmetry. The
@@ -115,16 +108,14 @@ public:
         *  @param i1 First index
         *  @param i2 Second index
         *  @param i3 Third index
-        *  @param i4 Fourth index
-        *  @return newly constructed indexed object */
+        *  @param i4 Fourth index */
        indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2, const ex & i3, const ex & i4);
 
        /** Construct indexed object with a specified vector of indices. The indices
         *  must be of class idx.
         *
         *  @param b Base expression
-        *  @param iv Vector of indices
-        *  @return newly constructed indexed object */
+        *  @param iv Vector of indices */
        indexed(const ex & b, const exvector & iv);
 
        /** Construct indexed object with a specified vector of indices and
@@ -132,8 +123,7 @@ public:
         *
         *  @param b Base expression
         *  @param symm Symmetry of indices
-        *  @param iv Vector of indices
-        *  @return newly constructed indexed object */
+        *  @param iv Vector of indices */
        indexed(const ex & b, const symmetry & symm, const exvector & iv);
 
        // internal constructors
index 99959a554920f61d29df1043e0607cfa8776481f..b72d81bdfe8364c37f14df1e7a45558edfe5ace5 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's initially known functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -1021,6 +1021,20 @@ static ex Order_imag_part(const ex & x)
        return Order(x).hold();
 }
 
+static ex Order_power(const ex & x, const ex & e)
+{
+       // Order(x)^e -> Order(x^e) for positive integer e
+       if (is_exactly_a<numeric>(e) && e.info(info_flags::posint))
+               return Order(pow(x, e));
+       // NB: For negative exponents, the above could be wrong.
+       // This is because series() produces Order(x^n) to denote the order where
+       // it gave up. So, Order(x^n) can also be an x^(n+1) term if the x^n term
+       // vanishes. In this situation, 1/Order(x^n) can also be a x^(-n-1) term.
+       // Transforming it to Order(x^-n) would miss that.
+
+       return power(Order(x), e).hold();
+}
+
 static ex Order_expl_derivative(const ex & arg, const symbol & s)
 {
        return Order(arg.diff(s));
@@ -1032,7 +1046,8 @@ REGISTER_FUNCTION(Order, eval_func(Order_eval).
                          expl_derivative_func(Order_expl_derivative).
                          conjugate_func(Order_conjugate).
                          real_part_func(Order_real_part).
-                         imag_part_func(Order_imag_part));
+                         imag_part_func(Order_imag_part).
+                         power_func(Order_power));
 
 //////////
 // Solve linear system
index 5ddc68da45a514db7ef2131cf07691183c281007..c49e8519cde033d6f90f23d9b74e83c4a82b8bea 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's initially known functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -177,6 +177,32 @@ template<> inline bool is_the_function<psi_SERIAL>(const ex & x)
        return is_the_function<psi1_SERIAL>(x) || is_the_function<psi2_SERIAL>(x);
 }
        
+/** Complete elliptic integral of the first kind. */
+DECLARE_FUNCTION_1P(EllipticK)
+
+/** Complete elliptic integral of the second kind. */
+DECLARE_FUNCTION_1P(EllipticE)
+
+// overloading at work: we cannot use the macros here
+/** Iterated integral. */
+class iterated_integral2_SERIAL { public: static unsigned serial; };
+template<typename T1, typename T2>
+inline function iterated_integral(const T1& kernel_lst, const T2& lambda) {
+       return function(iterated_integral2_SERIAL::serial, ex(kernel_lst), ex(lambda));
+}
+/** Iterated integral with explicit truncation. */
+class iterated_integral3_SERIAL { public: static unsigned serial; };
+template<typename T1, typename T2, typename T3>
+inline function iterated_integral(const T1& kernel_lst, const T2& lambda, const T3& N_trunc) {
+       return function(iterated_integral3_SERIAL::serial, ex(kernel_lst), ex(lambda), ex(N_trunc));
+}
+class iterated_integral_SERIAL;
+template<> inline bool is_the_function<iterated_integral_SERIAL>(const ex& x)
+{
+       return is_the_function<iterated_integral2_SERIAL>(x) || is_the_function<iterated_integral3_SERIAL>(x);
+}
+
+
 /** Factorial function. */
 DECLARE_FUNCTION_1P(factorial)
 
diff --git a/ginac/inifcns_elliptic.cpp b/ginac/inifcns_elliptic.cpp
new file mode 100644 (file)
index 0000000..4ea7bf2
--- /dev/null
@@ -0,0 +1,632 @@
+/** @file inifcns_elliptic.cpp
+ *
+ *  Implementation of some special functions related to elliptic curves
+ *
+ *  The functions are:
+ *    complete elliptic integral of the first kind        EllipticK(k)
+ *    complete elliptic integral of the second kind       EllipticE(k)
+ *    iterated integral                                   iterated_integral(a,y) or iterated_integral(a,y,N_trunc)
+ *
+ *  Some remarks:
+ *
+ *    - All formulae used can be looked up in the following publication:
+ *      [WW] Numerical evaluation of iterated integrals related to elliptic Feynman integrals, M.Walden, S.Weinzierl, arXiv:2010.05271
+ *
+ *    - When these routines and methods are used for scientific work that leads to publication in a scientific journal, 
+ *      please refer to this program as : 
+ *       M.Walden, S.Weinzierl, "Numerical evaluation of iterated integrals related to elliptic Feynman integrals", arXiv:2010.05271
+ *
+ *    - As these routines build on the core part of GiNaC, it is also polite to acknowledge
+ *       C. Bauer, A. Frink, R. Kreckel, "Introduction to the GiNaC Framework for Symbolic Computation within the C++ Programming Language", 
+ *       J. Symbolic Computations 33, 1 (2002), cs.sc/0004015
+ *
+ */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "inifcns.h"
+
+#include "add.h"
+#include "constant.h"
+#include "lst.h"
+#include "mul.h"
+#include "numeric.h"
+#include "operators.h"
+#include "power.h"
+#include "pseries.h"
+#include "relational.h"
+#include "symbol.h"
+#include "utils.h"
+#include "wildcard.h"
+
+#include "integration_kernel.h"
+#include "utils_multi_iterator.h"
+
+#include <cln/cln.h>
+#include <sstream>
+#include <stdexcept>
+#include <vector>
+#include <cmath>
+
+namespace GiNaC {
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Complete elliptic integrals
+//
+// helper functions
+//
+//////////////////////////////////////////////////////////////////////
+
+
+// anonymous namespace for helper function
+namespace {
+
+// Computes the arithmetic geometric of two numbers a_0 and b_0
+cln::cl_N arithmetic_geometric_mean(const cln::cl_N & a_0, const cln::cl_N & b_0)
+{
+       cln::cl_N a_old = a_0 * cln::cl_float(1, cln::float_format(Digits));
+       cln::cl_N b_old = b_0 * cln::cl_float(1, cln::float_format(Digits));
+       cln::cl_N a_new;
+       cln::cl_N b_new;
+       cln::cl_N res = a_old;
+       cln::cl_N resbuf;
+       do {
+               resbuf = res;
+
+                a_new = (a_old+b_old)/2;
+                b_new = sqrt(a_old*b_old);
+
+               if ( ( abs(a_new-b_new) > abs(a_new+b_new) ) 
+                    || 
+                    ( (abs(a_new-b_new) == abs(a_new+b_new)) && (imagpart(b_new/a_new) <= 0) ) ) {
+                       b_new *= -1;
+               }
+
+               res = a_new;
+               a_old = a_new;
+               b_old = b_new;
+    
+       } while (res != resbuf);
+       return res;
+}
+
+// Computes
+//  a0^2 - sum_{n=0}^infinity 2^{n-1}*c_n^2
+// with
+//  c_{n+1} = c_n^2/4/a_{n+1}
+//
+// Needed for the complete elliptic integral of the second kind.
+//
+cln::cl_N agm_helper_second_kind(const cln::cl_N & a_0, const cln::cl_N & b_0, const cln::cl_N & c_0)
+{
+       cln::cl_N a_old = a_0 * cln::cl_float(1, cln::float_format(Digits));
+       cln::cl_N b_old = b_0 * cln::cl_float(1, cln::float_format(Digits));
+       cln::cl_N c_old = c_0 * cln::cl_float(1, cln::float_format(Digits));
+       cln::cl_N a_new;
+       cln::cl_N b_new;
+       cln::cl_N c_new;
+       cln::cl_N res = square(a_old)-square(c_old)/2;
+       cln::cl_N resbuf;
+       cln::cl_N pre = cln::cl_float(1, cln::float_format(Digits));
+       do {
+               resbuf = res;
+
+                a_new = (a_old+b_old)/2;
+                b_new = sqrt(a_old*b_old);
+
+               if ( ( abs(a_new-b_new) > abs(a_new+b_new) ) 
+                    || 
+                    ( (abs(a_new-b_new) == abs(a_new+b_new)) && (imagpart(b_new/a_new) <= 0) ) ) {
+                       b_new *= -1;
+               }
+
+               c_new = square(c_old)/4/a_new;
+
+               res -= pre*square(c_new);
+
+               a_old = a_new;
+               b_old = b_new;
+               c_old = c_new;
+               pre *= 2;
+    
+       } while (res != resbuf);
+       return res;
+}
+
+
+} // end of anonymous namespace
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Complete elliptic integrals
+//
+// GiNaC function
+//
+//////////////////////////////////////////////////////////////////////
+
+static ex EllipticK_evalf(const ex& k)
+{
+       if ( !k.info(info_flags::numeric) ) {
+               return EllipticK(k).hold();
+       }
+     
+       cln::cl_N kbar = sqrt(1-square(ex_to<numeric>(k).to_cl_N()));
+
+       ex result = Pi/2/numeric(arithmetic_geometric_mean(1,kbar));
+
+       return result.evalf();
+}
+
+
+static ex EllipticK_eval(const ex& k)
+{
+       if (k == _ex0) {
+               return Pi/2;
+       }
+
+       if ( k.info(info_flags::numeric) && !k.info(info_flags::crational) ) {
+               return EllipticK(k).evalf();
+       }
+
+       return EllipticK(k).hold();
+}
+
+
+static ex EllipticK_deriv(const ex& k, unsigned deriv_param)
+{
+        return -EllipticK(k)/k + EllipticE(k)/k/(1-k*k);
+}
+
+
+static ex EllipticK_series(const ex& k, const relational& rel, int order, unsigned options)
+{       
+       const ex k_pt = k.subs(rel, subs_options::no_pattern);
+
+       if (k_pt == _ex0) {
+               const symbol s;
+               ex ser;
+               // manually construct the primitive expansion
+               for (int i=0; i<(order+1)/2; ++i)
+               {
+                       ser += Pi/2 * numeric(cln::square(cln::binomial(2*i,i))) * pow(s/4,2*i);
+               }
+               // substitute the argument's series expansion
+               ser = ser.subs(s==k.series(rel, order), subs_options::no_pattern);
+               // maybe that was terminating, so add a proper order term
+               epvector nseq { expair(Order(_ex1), order) };
+               ser += pseries(rel, std::move(nseq));
+               // reexpanding it will collapse the series again
+               return ser.series(rel, order);
+       }
+
+       if ( (k_pt == _ex1) || (k_pt == _ex_1) ) {
+               throw std::runtime_error("EllipticK_series: don't know how to do the series expansion at this point!");
+       }
+
+       // all other cases
+       throw do_taylor();
+}
+
+static void EllipticK_print_latex(const ex& k, const print_context& c)
+{
+       c.s << "\\mathrm{K}(";
+       k.print(c);
+       c.s << ")";
+}
+
+
+REGISTER_FUNCTION(EllipticK,
+                  evalf_func(EllipticK_evalf).
+                  eval_func(EllipticK_eval).
+                  derivative_func(EllipticK_deriv).
+                  series_func(EllipticK_series).
+                  print_func<print_latex>(EllipticK_print_latex).
+                  do_not_evalf_params());
+
+
+static ex EllipticE_evalf(const ex& k)
+{
+       if ( !k.info(info_flags::numeric) ) {
+               return EllipticE(k).hold();
+       }
+
+       cln::cl_N kbar = sqrt(1-square(ex_to<numeric>(k).to_cl_N()));
+
+       ex result = Pi/2 * numeric( agm_helper_second_kind(1,kbar,ex_to<numeric>(k).to_cl_N()) / arithmetic_geometric_mean(1,kbar) );
+
+       return result.evalf();
+}
+
+
+static ex EllipticE_eval(const ex& k)
+{
+       if (k == _ex0) {
+               return Pi/2;
+       }
+
+       if ( (k == _ex1) || (k == _ex_1) ) {
+               return 1;
+       }
+
+       if ( k.info(info_flags::numeric) && !k.info(info_flags::crational) ) {
+               return EllipticE(k).evalf();
+       }
+
+       return EllipticE(k).hold();
+}
+
+
+static ex EllipticE_deriv(const ex& k, unsigned deriv_param)
+{
+        return -EllipticK(k)/k + EllipticE(k)/k;
+}
+
+
+static ex EllipticE_series(const ex& k, const relational& rel, int order, unsigned options)
+{       
+       const ex k_pt = k.subs(rel, subs_options::no_pattern);
+
+       if (k_pt == _ex0) {
+               const symbol s;
+               ex ser;
+               // manually construct the primitive expansion
+               for (int i=0; i<(order+1)/2; ++i)
+               {
+                       ser -= Pi/2 * numeric(cln::square(cln::binomial(2*i,i)))/(2*i-1) * pow(s/4,2*i);
+               }
+               // substitute the argument's series expansion
+               ser = ser.subs(s==k.series(rel, order), subs_options::no_pattern);
+               // maybe that was terminating, so add a proper order term
+               epvector nseq { expair(Order(_ex1), order) };
+               ser += pseries(rel, std::move(nseq));
+               // reexpanding it will collapse the series again
+               return ser.series(rel, order);
+       }
+
+       if ( (k_pt == _ex1) || (k_pt == _ex_1) ) {
+               throw std::runtime_error("EllipticE_series: don't know how to do the series expansion at this point!");
+       }
+
+       // all other cases
+       throw do_taylor();
+}
+
+static void EllipticE_print_latex(const ex& k, const print_context& c)
+{
+       c.s << "\\mathrm{K}(";
+       k.print(c);
+       c.s << ")";
+}
+
+
+REGISTER_FUNCTION(EllipticE,
+                  evalf_func(EllipticE_evalf).
+                  eval_func(EllipticE_eval).
+                  derivative_func(EllipticE_deriv).
+                  series_func(EllipticE_series).
+                  print_func<print_latex>(EllipticE_print_latex).
+                  do_not_evalf_params());
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Iterated integrals
+//
+// helper functions
+//
+//////////////////////////////////////////////////////////////////////
+
+// anonymous namespace for helper function
+namespace {
+
+// performs the actual series summation for an iterated integral
+cln::cl_N iterated_integral_do_sum(const std::vector<int> & m, const std::vector<const integration_kernel *> & kernel, const cln::cl_N & lambda, int N_trunc)
+{
+        if ( cln::zerop(lambda) ) {
+               return 0;
+       }
+
+       cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
+
+       const int depth = m.size();
+
+       cln::cl_N res = 0;
+       cln::cl_N resbuf;
+       cln::cl_N subexpr;
+
+       if ( N_trunc == 0 ) {
+               // sum until precision is reached
+               bool flag_accidental_zero = false;
+
+               int N = 1;
+
+               do {
+                       resbuf = res;
+
+                       if ( depth > 1 ) {
+                               subexpr = 0;
+                               multi_iterator_ordered_eq<int> i_multi(1,N+1,depth-1);
+                               for( i_multi.init(); !i_multi.overflow(); i_multi++) {
+                                       cln::cl_N tt = one;
+                                       for (int j=1; j<depth; j++) {
+                                               if ( j==1 ) {
+                                                       tt = tt * kernel[0]->series_coeff(N-i_multi[depth-2]) / cln::expt(cln::cl_I(i_multi[depth-2]),m[1]);
+                                               }
+                                               else {
+                                                       tt = tt * kernel[j-1]->series_coeff(i_multi[depth-j]-i_multi[depth-j-1]) / cln::expt(cln::cl_I(i_multi[depth-j-1]),m[j]);
+                                               }
+                                       }
+                                       tt = tt * kernel[depth-1]->series_coeff(i_multi[0]);
+                                       subexpr += tt;
+                               }
+                       }
+                       else {
+                               // depth == 1
+                               subexpr = kernel[0]->series_coeff(N) * one;
+                       }
+                       flag_accidental_zero = cln::zerop(subexpr);
+                       res += cln::expt(lambda, N) / cln::expt(cln::cl_I(N),m[0]) * subexpr;
+                       N++;
+
+               } while ( (res != resbuf) || flag_accidental_zero );
+       }
+       else {
+               // N_trunc > 0, sum up the first N_trunc terms
+               for (int N=1; N<=N_trunc; N++) {
+                       if ( depth > 1 ) {
+                               subexpr = 0;
+                               multi_iterator_ordered_eq<int> i_multi(1,N+1,depth-1);
+                               for( i_multi.init(); !i_multi.overflow(); i_multi++) {
+                                       cln::cl_N tt = one;
+                                       for (int j=1; j<depth; j++) {
+                                               if ( j==1 ) {
+                                                       tt = tt * kernel[0]->series_coeff(N-i_multi[depth-2]) / cln::expt(cln::cl_I(i_multi[depth-2]),m[1]);
+                                               }
+                                               else {
+                                                       tt = tt * kernel[j-1]->series_coeff(i_multi[depth-j]-i_multi[depth-j-1]) / cln::expt(cln::cl_I(i_multi[depth-j-1]),m[j]);
+                                               }
+                                       }
+                                       tt = tt * kernel[depth-1]->series_coeff(i_multi[0]);
+                                       subexpr += tt;
+                               }
+                       }
+                       else {
+                               // depth == 1
+                               subexpr = kernel[0]->series_coeff(N) * one;
+                       }
+                       res += cln::expt(lambda, N) / cln::expt(cln::cl_I(N),m[0]) * subexpr;
+               }
+       }
+
+       return res;
+}
+
+// figure out the number of basic_log_kernels before a non-basic_log_kernel
+cln::cl_N iterated_integral_prepare_m_lst(const std::vector<const integration_kernel *> & kernel_in, const cln::cl_N & lambda, int N_trunc)
+{
+       size_t depth = kernel_in.size();
+
+       std::vector<int> m;
+       m.reserve(depth);
+
+       std::vector<const integration_kernel *> kernel;
+       kernel.reserve(depth);
+
+       int n = 1;
+
+       for (const auto & it : kernel_in) {
+               if ( is_a<basic_log_kernel>(*it) ) {
+                       n++;
+               }
+               else {
+                       m.push_back(n);
+                       kernel.push_back( &ex_to<integration_kernel>(*it) );
+                       n = 1;
+               }
+       }
+
+       cln::cl_N result = iterated_integral_do_sum(m, kernel, lambda, N_trunc);
+
+       return result;
+}
+
+// shuffle to remove trailing zeros,
+// integration kernels, which are not basic_log_kernels, are treated as regularised kernels
+cln::cl_N iterated_integral_shuffle(const std::vector<const integration_kernel *> & kernel, const cln::cl_N & lambda, int N_trunc)
+{
+        cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
+
+       const size_t depth = kernel.size();
+
+       size_t i_trailing = 0;
+       for (size_t i=0; i<depth; i++) {
+               if ( !(is_a<basic_log_kernel>(*(kernel[i]))) ) {
+                       i_trailing = i+1;
+               }
+       }
+
+       if ( i_trailing == 0 ) {
+               return cln::expt(cln::log(lambda), depth) / cln::factorial(depth) * one;
+       }
+
+       if ( i_trailing == depth ) {
+               return iterated_integral_prepare_m_lst(kernel, lambda, N_trunc);
+       }
+
+       // shuffle
+       std::vector<const integration_kernel *> a,b;
+       for (size_t i=0; i<i_trailing; i++) {
+               a.push_back(kernel[i]);
+       }
+       for (size_t i=i_trailing; i<depth; i++) {
+               b.push_back(kernel[i]);
+       }
+
+       cln::cl_N result = iterated_integral_prepare_m_lst(a, lambda, N_trunc) * cln::expt(cln::log(lambda), depth-i_trailing) / cln::factorial(depth-i_trailing);
+       multi_iterator_shuffle_prime<const integration_kernel *> i_shuffle(a,b);
+       for( i_shuffle.init(); !i_shuffle.overflow(); i_shuffle++) {
+               std::vector<const integration_kernel *> new_kernel;
+               new_kernel.reserve(depth);
+               for (size_t i=0; i<depth; i++) {
+                       new_kernel.push_back(i_shuffle[i]);
+               }
+
+               result -= iterated_integral_shuffle(new_kernel, lambda, N_trunc);
+       }
+
+       return result;
+}
+
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////
+//
+// Iterated integrals
+//
+// GiNaC function
+//
+//////////////////////////////////////////////////////////////////////
+
+static ex iterated_integral_evalf_impl(const ex& kernel_lst, const ex& lambda, const ex& N_trunc)
+{
+        // sanity check
+       if ((!kernel_lst.info(info_flags::list)) || (!lambda.evalf().info(info_flags::numeric)) || (!N_trunc.info(info_flags::nonnegint))) {
+               return iterated_integral(kernel_lst,lambda,N_trunc).hold();
+       }
+
+        lst k_lst = ex_to<lst>(kernel_lst);
+
+       bool flag_not_numeric = false;
+       for (const auto & it : k_lst) {
+               if ( !is_a<integration_kernel>(it) ) {
+                       flag_not_numeric = true;
+               }
+       }
+       if ( flag_not_numeric) {
+               return iterated_integral(kernel_lst,lambda,N_trunc).hold();
+       }
+
+       for (const auto & it : k_lst) {
+               if ( !(ex_to<integration_kernel>(it).is_numeric()) ) {
+                       flag_not_numeric = true;
+               }
+       }
+       if ( flag_not_numeric) {
+               return iterated_integral(kernel_lst,lambda,N_trunc).hold();
+       }
+
+       // now we know that iterated_integral gives a number
+
+       int N_trunc_int = ex_to<numeric>(N_trunc).to_int();
+
+       // check trailing zeros
+       const size_t depth = k_lst.nops();
+
+       std::vector<const integration_kernel *> kernel_vec;
+       kernel_vec.reserve(depth);
+
+       for (const auto & it : k_lst) {
+               kernel_vec.push_back( &ex_to<integration_kernel>(it) );
+       }
+
+       size_t i_trailing = 0;
+       for (size_t i=0; i<depth; i++) {
+               if ( !(kernel_vec[i]->has_trailing_zero()) ) {
+                       i_trailing = i+1;
+               }
+       }
+
+       // split integral into regularised integrals and trailing basic_log_kernels
+       // non-basic_log_kernels are treated as regularised kernels in call to iterated_integral_shuffle
+       cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
+       cln::cl_N lambda_cln = ex_to<numeric>(lambda.evalf()).to_cl_N();
+       basic_log_kernel L0 = basic_log_kernel();
+
+       cln::cl_N result;
+       if ( is_a<basic_log_kernel>(*(kernel_vec[depth-1])) ) {
+               result = 0;
+       }
+       else {
+               result = iterated_integral_shuffle(kernel_vec, lambda_cln, N_trunc_int);
+       }
+
+       cln::cl_N coeff = one;
+       for (size_t i_plus=depth; i_plus>i_trailing; i_plus--) {
+               coeff = coeff * kernel_vec[i_plus-1]->series_coeff(0);
+               kernel_vec[i_plus-1] = &L0;
+               if ( i_plus==i_trailing+1 ) {
+                       result += coeff * iterated_integral_shuffle(kernel_vec, lambda_cln, N_trunc_int);
+               }
+               else {
+                       if ( !(is_a<basic_log_kernel>(*(kernel_vec[i_plus-2]))) ) {
+                               result += coeff * iterated_integral_shuffle(kernel_vec, lambda_cln, N_trunc_int);
+                       }
+               }
+       }
+
+       return numeric(result);
+}
+
+static ex iterated_integral2_evalf(const ex& kernel_lst, const ex& lambda)
+{
+       return iterated_integral_evalf_impl(kernel_lst,lambda,0);
+}
+
+static ex iterated_integral3_evalf(const ex& kernel_lst, const ex& lambda, const ex& N_trunc)
+{
+       return iterated_integral_evalf_impl(kernel_lst,lambda,N_trunc);
+}
+
+static ex iterated_integral2_eval(const ex& kernel_lst, const ex& lambda)
+{
+       if ( lambda.info(info_flags::numeric) && !lambda.info(info_flags::crational) ) {
+               return iterated_integral(kernel_lst,lambda).evalf();
+       }
+
+       return iterated_integral(kernel_lst,lambda).hold();
+}
+
+static ex iterated_integral3_eval(const ex& kernel_lst, const ex& lambda, const ex& N_trunc)
+{
+       if ( lambda.info(info_flags::numeric) && !lambda.info(info_flags::crational) ) {
+               return iterated_integral(kernel_lst,lambda,N_trunc).evalf();
+       }
+
+       return iterated_integral(kernel_lst,lambda,N_trunc).hold();
+}
+
+unsigned iterated_integral2_SERIAL::serial =
+       function::register_new(function_options("iterated_integral", 2).
+                              eval_func(iterated_integral2_eval).
+                              evalf_func(iterated_integral2_evalf).
+                               do_not_evalf_params().
+                              overloaded(2));
+
+unsigned iterated_integral3_SERIAL::serial =
+       function::register_new(function_options("iterated_integral", 3).
+                              eval_func(iterated_integral3_eval).
+                              evalf_func(iterated_integral3_evalf).
+                               do_not_evalf_params().
+                              overloaded(2));
+
+} // namespace GiNaC
+
index c6c7f9574f25defef9db32a58145094be7360074..d4b425fb003d904b42c168b973c375638c39ba10 100644 (file)
@@ -4,7 +4,7 @@
  *  some related stuff. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index f040e8ad64df2aab86a5d8dda2d3b9c51c3e8b3d..e69cdb4014612f9cdbacc8389a4b17db244c7890 100644 (file)
@@ -47,7 +47,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -1013,21 +1013,25 @@ G_do_hoelder(std::vector<cln::cl_N> x, /* yes, it's passed by value */
        for (std::size_t i = 0; i < size; ++i)
                x[i] = x[i]/y;
 
+        // 24.03.2021: this block can be outside the loop over r 
+       cln::cl_RA p(2);
+       bool adjustp;
+       do {
+               adjustp = false;
+               for (std::size_t i = 0; i < size; ++i) {
+                        // 24.03.2021: replaced (x[i] == cln::cl_RA(1)/p) by (cln::zerop(x[i] - cln::cl_RA(1)/p)
+                        //             in the case where we compare a float with a rational, CLN behaves differently in the two versions
+                       if (cln::zerop(x[i] - cln::cl_RA(1)/p) ) {
+                               p = p/2 + cln::cl_RA(3)/2;
+                               adjustp = true;
+                               continue;
+                       }
+               }
+       } while (adjustp);
+       cln::cl_RA q = p/(p-1);
+
        for (std::size_t r = 0; r <= size; ++r) {
                cln::cl_N buffer(1 & r ? -1 : 1);
-               cln::cl_RA p(2);
-               bool adjustp;
-               do {
-                       adjustp = false;
-                       for (std::size_t i = 0; i < size; ++i) {
-                               if (x[i] == cln::cl_RA(1)/p) {
-                                       p = p/2 + cln::cl_RA(3)/2;
-                                       adjustp = true;
-                                       continue;
-                               }
-                       }
-               } while (adjustp);
-               cln::cl_RA q = p/(p-1);
                std::vector<cln::cl_N> qlstx;
                std::vector<int> qlsts;
                for (std::size_t j = r; j >= 1; --j) {
@@ -3223,7 +3227,6 @@ static ex H_evalf(const ex& x1, const ex& x2)
                        return filter(H(x1, xtemp).hold()).subs(xtemp==x2).evalf();
                }
                // ... and expand parameter notation
-               bool has_minus_one = false;
                lst m;
                for (const auto & it : morg) {
                        if (it > 1) {
@@ -3236,7 +3239,6 @@ static ex H_evalf(const ex& x1, const ex& x2)
                                        m.append(0);
                                }
                                m.append(-1);
-                               has_minus_one = true;
                        } else {
                                m.append(it);
                        }
@@ -3297,7 +3299,14 @@ static ex H_evalf(const ex& x1, const ex& x2)
                        }
                        return res.subs(xtemp == numeric(x)).evalf();
                }
-               
+
+               // check for letters (-1)
+               bool has_minus_one = false;
+               for (const auto & it : m) {
+                       if (it == -1)
+                               has_minus_one = true;
+               }
+
                // check transformations for 0.95 <= |x| < 2.0
                
                // |(1-x)/(1+x)| < 0.9 -> circular area with center=9.53+0i and radius=9.47
@@ -3309,7 +3318,9 @@ static ex H_evalf(const ex& x1, const ex& x2)
                        // x -> 1-x
                        if (has_minus_one) {
                                map_trafo_H_convert_to_Li filter;
-                               return filter(H(m, numeric(x)).hold()).evalf();
+                                // 09.06.2021: bug fix: don't forget a possible minus sign from the case realpart(x) < 0
+                               res *= filter(H(m, numeric(x)).hold()).evalf();
+                               return res;
                        }
                        map_trafo_H_1mx trafo;
                        res *= trafo(H(m, xtemp).hold());
@@ -4061,7 +4072,8 @@ static ex zeta2_evalf(const ex& x, const ex& s)
                return numeric(zeta_do_Hoelder_convolution(xi, si));
        }
 
-       return zeta(x, s).hold();
+       // x and s are not lists: convert to lists
+       return zeta(lst{x}, lst{s}).evalf();
 }
 
 
index 232db8c59a25e2b0ab3fb1b06607d5e2a656ca1d..9a2a0b6c402bc6f666637ccadbd9c1331ec66b95 100644 (file)
@@ -4,7 +4,7 @@
  *  functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -128,13 +128,47 @@ static ex exp_conjugate(const ex & x)
        return exp(x.conjugate());
 }
 
+static ex exp_power(const ex & x, const ex & a)
+{
+       /*
+        * The power law (e^x)^a=e^(x*a) is used in two cases:
+        * a) a is an integer and x may be complex;
+        * b) both x and a are reals.
+        * Negative a is excluded to keep automatic simplifications like exp(x)/exp(x)=1.
+        */
+       if (a.info(info_flags::nonnegative)
+           && (a.info(info_flags::integer) || (x.info(info_flags::real) && a.info(info_flags::real))))
+               return exp(x*a);
+       else if (a.info(info_flags::negative)
+                && (a.info(info_flags::integer) || (x.info(info_flags::real) && a.info(info_flags::real))))
+               return power(exp(-x*a), _ex_1).hold();
+
+       return power(exp(x), a).hold();
+}
+
+static bool exp_info(const ex & x, unsigned inf)
+{
+       switch (inf) {
+       case info_flags::expanded:
+       case info_flags::real:
+               return x.info(inf);
+       case info_flags::positive:
+       case info_flags::nonnegative:
+               return x.info(info_flags::real);
+       default:
+               return false;
+       }
+}
+
 REGISTER_FUNCTION(exp, eval_func(exp_eval).
                        evalf_func(exp_evalf).
+                       info_func(exp_info).
                        expand_func(exp_expand).
                        derivative_func(exp_deriv).
                        real_part_func(exp_real_part).
                        imag_part_func(exp_imag_part).
                        conjugate_func(exp_conjugate).
+                       power_func(exp_power).
                        latex_name("\\exp"));
 
 //////////
@@ -197,7 +231,7 @@ static ex log_series(const ex &arg,
        // maybe substitution of rel into arg fails because of a pole
        try {
                arg_pt = arg.subs(rel, subs_options::no_pattern);
-       } catch (pole_error) {
+       } catch (pole_error &) {
                must_expand_arg = true;
        }
        // or we are at the branch point anyways
@@ -351,8 +385,21 @@ static ex log_conjugate(const ex & x)
        return conjugate_function(log(x)).hold();
 }
 
+static bool log_info(const ex & x, unsigned inf)
+{
+       switch (inf) {
+       case info_flags::expanded:
+               return x.info(inf);
+       case info_flags::real:
+               return x.info(info_flags::positive);
+       default:
+               return false;
+       }
+}
+
 REGISTER_FUNCTION(log, eval_func(log_eval).
                        evalf_func(log_evalf).
+                       info_func(log_info).
                        expand_func(log_expand).
                        derivative_func(log_deriv).
                        series_func(log_series).
@@ -460,8 +507,20 @@ static ex sin_conjugate(const ex & x)
        return sin(x.conjugate());
 }
 
+static bool trig_info(const ex & x, unsigned inf)
+{
+       switch (inf) {
+       case info_flags::expanded:
+       case info_flags::real:
+               return x.info(inf);
+       default:
+               return false;
+       }
+}
+
 REGISTER_FUNCTION(sin, eval_func(sin_eval).
                        evalf_func(sin_evalf).
+                       info_func(trig_info).
                        derivative_func(sin_deriv).
                        real_part_func(sin_real_part).
                        imag_part_func(sin_imag_part).
@@ -568,6 +627,7 @@ static ex cos_conjugate(const ex & x)
 }
 
 REGISTER_FUNCTION(cos, eval_func(cos_eval).
+                       info_func(trig_info).
                        evalf_func(cos_evalf).
                        derivative_func(cos_deriv).
                        real_part_func(cos_real_part).
@@ -693,6 +753,7 @@ static ex tan_conjugate(const ex & x)
 
 REGISTER_FUNCTION(tan, eval_func(tan_eval).
                        evalf_func(tan_evalf).
+                       info_func(trig_info).
                        derivative_func(tan_deriv).
                        series_func(tan_series).
                        real_part_func(tan_real_part).
@@ -767,8 +828,19 @@ static ex asin_conjugate(const ex & x)
        return conjugate_function(asin(x)).hold();
 }
 
+static bool asin_info(const ex & x, unsigned inf)
+{
+       switch (inf) {
+       case info_flags::expanded:
+               return x.info(inf);
+       default:
+               return false;
+       }
+}
+
 REGISTER_FUNCTION(asin, eval_func(asin_eval).
                         evalf_func(asin_evalf).
+                        info_func(asin_info).
                         derivative_func(asin_deriv).
                         conjugate_func(asin_conjugate).
                         latex_name("\\arcsin"));
@@ -842,6 +914,7 @@ static ex acos_conjugate(const ex & x)
 
 REGISTER_FUNCTION(acos, eval_func(acos_eval).
                         evalf_func(acos_evalf).
+                        info_func(asin_info). // Flags of acos are shared with asin functions
                         derivative_func(acos_deriv).
                         conjugate_func(acos_conjugate).
                         latex_name("\\arccos"));
@@ -959,8 +1032,24 @@ static ex atan_conjugate(const ex & x)
        return conjugate_function(atan(x)).hold();
 }
 
+static bool atan_info(const ex & x, unsigned inf)
+{
+       switch (inf) {
+       case info_flags::expanded:
+       case info_flags::real:
+               return x.info(inf);
+       case info_flags::positive:
+       case info_flags::negative:
+       case info_flags::nonnegative:
+               return x.info(info_flags::real) && x.info(inf);
+       default:
+               return false;
+       }
+}
+
 REGISTER_FUNCTION(atan, eval_func(atan_eval).
                         evalf_func(atan_evalf).
+                        info_func(atan_info).
                         derivative_func(atan_deriv).
                         series_func(atan_series).
                         conjugate_func(atan_conjugate).
@@ -1061,7 +1150,25 @@ static ex atan2_deriv(const ex & y, const ex & x, unsigned deriv_param)
        return -y*power(power(x,_ex2)+power(y,_ex2),_ex_1);
 }
 
+static bool atan2_info(const ex & y, const ex & x, unsigned inf)
+{
+       switch (inf) {
+       case info_flags::expanded:
+       case info_flags::real:
+               return y.info(inf) && x.info(inf);
+       case info_flags::positive:
+       case info_flags::negative:
+       case info_flags::nonnegative:
+               return y.info(info_flags::real) && x.info(info_flags::real)
+                       && y.info(inf);
+       default:
+               return false;
+       }
+}
+
 REGISTER_FUNCTION(atan2, eval_func(atan2_eval).
+                         evalf_func(atan2_evalf).
+                         info_func(atan2_info).
                          evalf_func(atan2_evalf).
                          derivative_func(atan2_deriv));
 
@@ -1143,6 +1250,7 @@ static ex sinh_conjugate(const ex & x)
 
 REGISTER_FUNCTION(sinh, eval_func(sinh_eval).
                         evalf_func(sinh_evalf).
+                        info_func(atan_info). // Flags of sinh are shared with atan functions
                         derivative_func(sinh_deriv).
                         real_part_func(sinh_real_part).
                         imag_part_func(sinh_imag_part).
@@ -1227,6 +1335,7 @@ static ex cosh_conjugate(const ex & x)
 
 REGISTER_FUNCTION(cosh, eval_func(cosh_eval).
                         evalf_func(cosh_evalf).
+                        info_func(exp_info). // Flags of cosh are shared with exp functions
                         derivative_func(cosh_deriv).
                         real_part_func(cosh_real_part).
                         imag_part_func(cosh_imag_part).
@@ -1331,6 +1440,7 @@ static ex tanh_conjugate(const ex & x)
 
 REGISTER_FUNCTION(tanh, eval_func(tanh_eval).
                         evalf_func(tanh_evalf).
+                        info_func(atan_info). // Flags of tanh are shared with atan functions
                         derivative_func(tanh_deriv).
                         series_func(tanh_series).
                         real_part_func(tanh_real_part).
@@ -1396,6 +1506,7 @@ static ex asinh_conjugate(const ex & x)
 
 REGISTER_FUNCTION(asinh, eval_func(asinh_eval).
                          evalf_func(asinh_evalf).
+                         info_func(atan_info). // Flags of asinh are shared with atan functions
                          derivative_func(asinh_deriv).
                          conjugate_func(asinh_conjugate));
 
@@ -1460,6 +1571,7 @@ static ex acosh_conjugate(const ex & x)
 
 REGISTER_FUNCTION(acosh, eval_func(acosh_eval).
                          evalf_func(acosh_evalf).
+                         info_func(asin_info). // Flags of acosh are shared with asin functions
                          derivative_func(acosh_deriv).
                          conjugate_func(acosh_conjugate));
 
@@ -1566,6 +1678,7 @@ static ex atanh_conjugate(const ex & x)
 
 REGISTER_FUNCTION(atanh, eval_func(atanh_eval).
                          evalf_func(atanh_evalf).
+                         info_func(asin_info). // Flags of atanh are shared with asin functions
                          derivative_func(atanh_deriv).
                          series_func(atanh_series).
                          conjugate_func(atanh_conjugate));
index 0b3800488bbad870dec9a30371cdadfb4fa7927d..db5a46c65e9de8efc8cedfac0adfd9cb0e04f44a 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's symbolic  integral. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@ namespace GiNaC {
 
 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(integral, basic,
   print_func<print_dflt>(&integral::do_print).
+  print_func<print_python>(&integral::do_print).
   print_func<print_latex>(&integral::do_print_latex))
 
 
index 8cbae7a1ea2319afbe9f52c6656c92b05a3ea9b3..91b078de247334cb1c304f07f82bb4c81f6f2fd3 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's symbolic  integral. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/ginac/integration_kernel.cpp b/ginac/integration_kernel.cpp
new file mode 100644 (file)
index 0000000..d224bd8
--- /dev/null
@@ -0,0 +1,2148 @@
+/** @file integration_kernel.cpp
+ *
+ *  Implementation of GiNaC's integration kernels for iterated integrals. */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "integration_kernel.h"
+#include "add.h"
+#include "mul.h"
+#include "operators.h"
+#include "power.h"
+#include "relational.h"
+#include "symbol.h"
+#include "constant.h"
+#include "numeric.h"
+#include "function.h"
+#include "pseries.h"
+#include "utils.h"
+#include "inifcns.h"
+
+#include <iostream>
+#include <stdexcept>
+#include <cln/cln.h>
+
+
+namespace GiNaC {
+
+// anonymous namespace for helper function
+namespace {
+
+/**
+ *
+ * Returns the Kronecker symbol in the case where
+ *  a: integer
+ *  n: unit or prime number
+ *
+ * If n is an odd prime number, the routine returns the Legendre symbol.
+ *
+ * If n is a unit (e.g n equals 1 or -1) or if n is an even prime number (the only case is n=2)
+ * the routine returns the special values defined below.
+ *
+ * Ref.: Toshitsune Miyake, Modular Forms, Chapter 3.1
+ *
+ */
+numeric kronecker_symbol_prime(const numeric & a, const numeric & n)
+{
+       if ( n == 1 ) {
+               return 1;
+       }
+       else if ( n == -1 ) {
+               if ( a >= 0 ) {
+                       return 1;
+               }
+               else {
+                       return -1;
+               }
+       }
+       else if ( n == 2 ) {
+               if ( GiNaC::smod(a,8) == 1 ) {
+                       return 1;
+               }
+               else if ( GiNaC::smod(a,8) == -1 ) {
+                       return 1;
+               }
+               else if  ( GiNaC::smod(a,8) == 3 ) {
+                       return -1;
+               }
+               else if ( GiNaC::smod(a,8) == -3 ) {
+                       return -1;
+               }
+               else {
+                       return 0;
+               }
+       }
+
+       // n is an odd prime number
+       return GiNaC::smod( pow(a,(n-1)/2), n);
+}
+
+/**
+ *
+ * n:     positive integer
+ *
+ * a:     discriminant of a quadratic field, defines primitive character phi
+ * b:     discriminant of a quadratic field, defines primitive character psi
+ * L=|a|: conductor of primitive character phi
+ * M=|b|: conductor of primitive character psi
+ *
+ * k:     modular weight
+ *
+ * This function computes
+ * \f[
+ *      \sum\limits_{d | n} \psi(d) \phi(n/d) d^{k-1}
+ * \f]
+ *
+ * Ref.: Eq.(5.3.1), William A. Stein, Modular Forms, A computational Approach;
+ *
+ *       Eq.(32), arXiv:1704.08895
+ *
+ */
+numeric divisor_function(const numeric & n, const numeric & a, const numeric & b, const numeric & k)
+{
+       ex res = 0;
+
+       for (numeric i1=1; i1<=n; i1++) {
+               if ( irem(n,i1) == 0 ) {
+                       numeric ratio = n/i1;
+                       res += primitive_dirichlet_character(ratio,a) * primitive_dirichlet_character(i1,b) * pow(i1,k-1);
+               }
+       }
+
+       return ex_to<numeric>(res);
+}
+
+/**
+ *
+ * k:     modular weight
+ *
+ * a:     discriminant of a quadratic field, defines primitive character phi
+ * b:     discriminant of a quadratic field, defines primitive character psi
+ * L=|a|: conductor of primitive character phi
+ * M=|b|: conductor of primitive character psi
+ *
+ * This function computes the constant term of the q-expansion of an Eisenstein series.
+ *
+ * The coefficient is given by the equation below eq.(5.3.1) in William A. Stein, Modular Forms, A computational Approach;
+ *
+ * or by eq.(33), arXiv:1704.08895
+ *
+ */
+numeric coefficient_a0(const numeric & k, const numeric & a, const numeric & b)
+{
+       ex conductor = abs(a);
+
+       numeric a0;
+       if ( conductor == 1 ) {
+               a0 = -numeric(1,2)/k*generalised_Bernoulli_number(k,b);
+       }
+       else {
+               a0 = 0;
+       }
+
+       return a0;
+}
+
+/**
+ *
+ * k:     modular weight
+ * q:     exp(2 Pi I tau/M)
+ *
+ * a:     discriminant of a quadratic field, defines primitive character phi
+ * b:     discriminant of a quadratic field, defines primitive character psi
+ * L=|a|: conductor of primitive character phi
+ * M=|b|: conductor of primitive character psi
+ *
+ * N:     truncation order
+ *
+ * Returns the q-expansion of an Eisenstein to order N (the q^(N-1)-term is included, q^N is neglected).
+ *
+ * Ref.: Eq.(5.3.1), William A. Stein, Modular Forms, A computational Approach;
+ *
+ *       Eq.(32), arXiv:1704.08895
+ *
+ */
+ex eisenstein_series(const numeric & k, const ex & q, const numeric & a, const numeric & b, const numeric & N)
+{
+       ex res = coefficient_a0(k,a,b);
+
+       for (numeric i1=1; i1<N; i1++) {
+               res += divisor_function(i1,a,b,k) * pow(q,i1);
+       }
+
+       return res;
+}
+
+/**
+ *
+ * Returns the q_N-expansion of the Eisenstein series E_{k,a,b}(K tau_N)
+ *
+ */
+ex E_eisenstein_series(const ex & q, const numeric & k, const numeric & N_level, const numeric & a, const numeric & b, const numeric & K, const numeric & N_order)
+{
+       int N_order_int = N_order.to_int();
+
+       ex res = eisenstein_series(k,pow(q,K),a,b,iquo(N_order,K));
+
+       res += Order(pow(q,N_order_int));
+       res = res.series(q,N_order_int);
+
+       return res;
+}
+
+/**
+ *
+ * In weight 2 we have a special case for trivial Dirichlet characters:
+ * Returns the q_N-expansion of the Eisenstein series E_{2,1,1}(tau_N) - K E_{2,1,1}(K tau_N). 
+ *
+ */
+ex B_eisenstein_series(const ex & q, const numeric & N_level, const numeric & K, const numeric & N_order)
+{
+       int N_order_int = N_order.to_int();
+
+       ex res = eisenstein_series(2,q,1,1,N_order) - K*eisenstein_series(2,pow(q,K),1,1,iquo(N_order,K));
+
+       res += Order(pow(q,N_order_int));
+       res = res.series(q,N_order_int);
+
+       return res;
+}
+
+/**
+ *
+ * A helper function to expand polynomials in Eisenstein series.
+ *
+ */
+struct subs_q_expansion : public map_function
+{
+       subs_q_expansion(const ex & arg_qbar, int arg_order) : qbar(arg_qbar), order(arg_order)
+               {}
+
+       ex operator()(const ex & e)
+               {
+                       if ( is_a<Eisenstein_kernel>(e) || is_a<Eisenstein_h_kernel>(e) ) {
+                               return series_to_poly(e.series(qbar,order));
+                       }
+                       else {
+                               return e.map(*this);
+                       }
+               }
+
+       ex qbar;
+       int order;
+};
+
+/**
+ *
+ * \f[
+ *     Li_{-n}(x),  n>=0
+ * \f]
+ *
+ * This is a rational function in x.
+ *
+ * To speed things up, we cache it.
+ *
+ */
+class Li_negative
+{
+       // ctors
+public:
+       Li_negative();
+
+       // non-virtual functions 
+public:
+       ex get_symbolic_value(int n, const ex & x_val);
+       ex get_numerical_value(int n, const ex & x_val);
+
+       // member variables :
+protected:
+       static std::vector<ex> cache_vec;
+       static symbol x;
+};
+
+
+Li_negative::Li_negative() {}
+
+ex Li_negative::get_symbolic_value(int n, const ex & x_val)
+{
+       int n_cache = cache_vec.size();
+
+       if ( n >= n_cache ) {
+               for (int j=n_cache; j<=n; j++) {
+                       ex f;
+                       if ( j == 0 ) {
+                               f = x/(1-x);
+                       }
+                       else {
+                               f = normal( x*diff(cache_vec[j-1],x));
+                       }
+                       cache_vec.push_back( f );
+               }
+       }
+
+       return cache_vec[n].subs(x==x_val);
+}
+
+ex Li_negative::get_numerical_value(int n, const ex & x_val)
+{
+       symbol x_symb("x_symb");
+
+       ex f = this->get_symbolic_value(n,x_symb);
+
+       ex res = f.subs(x_symb==x_val).evalf();
+
+       return res;
+}
+
+// initialise static data members
+std::vector<ex> Li_negative::cache_vec;
+symbol Li_negative::x = symbol("x");
+
+
+} // end of anonymous namespace
+
+/**
+ *
+ * Returns the decomposition of the positive integer n into prime numbers
+ * in the form
+ *  lst( lst(p1,...,pr), lst(a1,...,ar) )
+ * such that
+ *  n = p1^a1 ... pr^ar.
+ *
+ */
+ex ifactor(const numeric & n)
+{
+       if ( !n.is_pos_integer() ) throw (std::runtime_error("ifactor(): argument not a positive integer"));
+
+       lst p_lst, exp_lst;
+
+       // implementation for small integers
+       numeric n_temp = n;
+       for (numeric p=2; p<=n; p++) {
+               if ( p.info(info_flags::prime) ) {
+                       numeric exp_temp = 0;
+                       while ( irem(n_temp, p) == 0 ) {
+                               n_temp = n_temp/p;
+                               exp_temp++;
+                       }
+                       if ( exp_temp>0 ) {
+                               p_lst.append(p);
+                               exp_lst.append(exp_temp);
+                       }
+               }
+               if ( n_temp == 1 ) break;
+       }
+
+       if ( n_temp != 1 ) throw (std::runtime_error("ifactor(): probabilistic primality test failed"));
+
+       lst res = {p_lst,exp_lst};
+
+       return res;
+}
+
+/**
+ *
+ * Returns true if the integer n is either one or the discriminant of a quadratic number field.
+ *
+ * Returns false otherwise.
+ *
+ * Ref.: Toshitsune Miyake, Modular Forms, Chapter 3.1
+ *
+ */
+bool is_discriminant_of_quadratic_number_field(const numeric & n)
+{
+       if ( n == 0 ) {
+               return false;
+       }
+
+       if ( n == 1 ) {
+               return true;
+       }
+
+       lst prime_factorisation = ex_to<lst>(ifactor(abs(n)));
+       lst p_lst = ex_to<lst>(prime_factorisation.op(0));
+       lst e_lst = ex_to<lst>(prime_factorisation.op(1));
+
+       size_t n_primes = p_lst.nops();
+
+       if ( n_primes > 0 ) {
+               // take the last prime
+               numeric p = ex_to<numeric>(p_lst.op(n_primes-1));
+       
+               if ( p.is_odd() ) {
+                       if ( e_lst.op(n_primes-1) != 1 ) {
+                               return false;
+                       }
+
+                       numeric pstar = p;
+                       if ( mod(p,4) == 3 ) {
+                               pstar = -p;
+                       }
+                       return is_discriminant_of_quadratic_number_field(n/pstar);
+               }
+       }
+       // power of two now
+       if ( (n==-4) || (n==-8) || (n==8) || (n==-32) || (n==32) || (n==-64) || (n==128) ) {
+               return true; 
+       }
+
+       return false;
+}
+
+/**
+ *
+ * Returns the Kronecker symbol
+ *  a: integer
+ *  n: integer
+ *
+ * This routine defines
+ *  kronecker_symbol(1,0)   = 1
+ *  kronecker_symbol(-1,0)  = 1
+ *  kronecker_symbol(a,0)   = 0, a != 1,-1
+ *
+ * In particular
+ *  kronecker_symbol(-1,0) = 1 (in agreement with Sage)
+ *
+ * Ref.: Toshitsune Miyake, Modular Forms, Chapter 3.1
+ *
+ */
+numeric kronecker_symbol(const numeric & a, const numeric & n)
+{
+       // case n=0 first, include kronecker_symbol(0,0)=0
+       if ( n == 0 ) {
+               if ( (a == 1) || (a == -1) ) {
+                       return 1;
+               }
+               else {
+                       return 0;
+               }
+       }
+
+       numeric unit = 1;
+       numeric n_pos = n;
+       if ( n_pos<0 ) {
+               unit = -1;
+               n_pos = -n;
+       }
+
+       ex res = kronecker_symbol_prime(a,unit);
+
+       numeric n_odd = n_pos;
+       numeric alpha = 0;
+       while ( n_odd.is_even() ) {
+               alpha++;
+               n_odd = n_odd/2;
+       }
+       if ( alpha>0 ) {
+               res *= pow(kronecker_symbol_prime(a,2),alpha);
+       }
+
+       lst temp_lst = ex_to<lst>(ifactor(n_odd));
+       lst prime_lst = ex_to<lst>(temp_lst.op(0));
+       lst expo_lst = ex_to<lst>(temp_lst.op(1));
+
+       for (auto it_p = prime_lst.begin(), it_e = expo_lst.begin(); it_p != prime_lst.end(); it_p++, it_e++) {
+               res *= pow(kronecker_symbol_prime(a,ex_to<numeric>(*it_p)),ex_to<numeric>(*it_e));
+       }
+
+       return ex_to<numeric>(res);
+}
+
+/**
+ *
+ * Defines a primitive Dirichlet character through the Kronecker symbol.
+ *
+ *  n:  integer
+ *  a:  discriminant of a quadratic field
+ * |a|: conductor
+ *
+ * The character takes the values -1,0,1.
+ *
+ */
+numeric primitive_dirichlet_character(const numeric & n, const numeric & a)
+{
+       return kronecker_symbol(a,n);
+}
+
+/**
+ *
+ * Defines a Dirichlet character through the Kronecker symbol.
+ *
+ *  n:  integer
+ *  a:  discriminant of a quadratic field
+ * |a|: conductor
+ *  N:  modulus, needs to be multiple of |a|
+ *
+ * The character takes the values -1,0,1.
+ *
+ */
+numeric dirichlet_character(const numeric & n, const numeric & a, const numeric & N)
+{
+       if ( gcd(n,N) == 1 ) {
+               return primitive_dirichlet_character(n,a);
+       }
+
+       return 0;
+}
+
+/**
+ *
+ * The generalised Bernoulli number.
+ *
+ * k:     index / modular weight
+ *
+ * b:     discriminant of a quadratic field, defines primitive character psi
+ * M=|b|: conductor of primitive character psi
+ *
+ * The generalised Bernoulli number is computed from the series expansion of the generating function.
+ * The generating function is given in eq.(34), arXiv:1704.08895
+ *
+ */
+numeric generalised_Bernoulli_number(const numeric & k, const numeric & b)
+{
+       int k_int = k.to_int();
+       symbol x("x");
+
+       numeric conductor = abs(b);
+
+       ex gen_fct = 0;
+       for (numeric i1=1; i1<=conductor; i1++) {
+               gen_fct += primitive_dirichlet_character(i1,b) * x*exp(i1*x)/(exp(conductor*x)-1);
+       }
+
+       gen_fct = series_to_poly(gen_fct.series(x,k_int+1));
+       ex B = factorial(k) * gen_fct.coeff(x,k_int);
+
+       return ex_to<numeric>(B);
+}
+
+/**
+ *
+ * The Bernoulli polynomials
+ *
+ */
+ex Bernoulli_polynomial(const numeric & k, const ex & x)
+{
+       int k_int = k.to_int();
+       symbol t("t");
+
+       ex gen_fct = t*exp(x*t)/(exp(t)-1);
+
+       gen_fct = series_to_poly(gen_fct.series(t,k_int+1));
+       ex B = factorial(k) * gen_fct.coeff(t,k_int);
+
+       return B;
+}
+
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(integration_kernel, basic,
+  print_func<print_context>(&integration_kernel::do_print))
+
+integration_kernel::integration_kernel() : inherited(), cache_step_size(100), series_vec()
+{
+}
+
+int integration_kernel::compare_same_type(const basic &other) const
+{
+       return 0;
+}
+
+ex integration_kernel::series(const relational & r, int order, unsigned options) const
+{
+       if ( r.rhs() != 0 ) {
+               throw (std::runtime_error("integration_kernel::series: non-zero expansion point not implemented"));
+       }
+
+       return Laurent_series(r.lhs(),order);
+}
+
+/**
+ *
+ * This routine returns true, if the integration kernel has a trailing zero.
+ *
+ */
+bool integration_kernel::has_trailing_zero(void) const
+{
+       if ( cln::zerop( series_coeff(0) ) ) {
+               return false;
+       }
+
+       return true;
+}
+
+/**
+ *
+ * This routine returns true, if the integration kernel can be evaluated numerically.
+ *
+ */
+bool integration_kernel::is_numeric(void) const
+{
+       return true;
+}
+
+/**
+ *
+ * Subclasses have either to implement series_coeff_impl
+ * or the two methods Laurent_series and uses_Laurent_series.
+ *
+ * The method series_coeff_impl can be used, if a single coefficient can be computed 
+ * independently of the others.
+ *
+ * The method Laurent_series can be used, if it is more efficient to compute a Laurent series
+ * in one shot and to determine a range of coefficients from this Laurent series.
+ *
+ */
+cln::cl_N integration_kernel::series_coeff(int i) const
+{
+       int n_vec = series_vec.size();
+
+       if ( i >= n_vec ) {
+               int N = cache_step_size*(i/cache_step_size+1);
+
+               if ( uses_Laurent_series() ) {
+                       symbol x("x");
+                       // series_vec[0] gives coefficient of 1/z, series_vec[N-1] coefficient of z^(N-2),
+                       // thus expansion up to order (N-1) is required
+                       ex temp = Laurent_series(x, N-1);
+                       for (int j=n_vec; j<N; j++) {
+                               series_vec.push_back( ex_to<numeric>(temp.coeff(x,j-1).evalf()).to_cl_N() );
+                       }
+               }
+               else {
+                       for (int j=n_vec; j<N; j++) {
+                               series_vec.push_back( series_coeff_impl(j) );
+                       }
+               }
+       }
+
+       return series_vec[i];
+}
+
+/**
+ *
+ * For \f$ \omega = d\lambda \f$ only the coefficient of \f$ \lambda^0 \f$ is non-zero.
+ *
+ * The i-th coefficient corresponds to the power \f$ \lambda^{i-1} \f$.
+ *
+ */
+cln::cl_N integration_kernel::series_coeff_impl(int i) const
+{
+       if ( i == 1 ) {
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ *
+ * Returns the Laurent series, starting possibly with the pole term.
+ * Neglected terms are of order \f$ O(x^order) \f$.
+ *
+ */
+ex integration_kernel::Laurent_series(const ex & x, int order) const
+{
+       ex res = 0;
+       for (int n=-1; n<order; n++) {
+               res += numeric(series_coeff(n+1)) * pow(x,n);
+       }
+       res += Order(pow(x,order));
+       res = res.series(x,order);
+
+       return res;
+}
+
+/**
+ *
+ * Evaluates the integrand at lambda.
+ *
+ */
+ex  integration_kernel::get_numerical_value(const ex & lambda, int N_trunc) const
+{
+       return get_numerical_value_impl(lambda, 1, 0, N_trunc);
+}
+
+/**
+ *
+ * Returns true, if the coefficients are computed from the Laurent series
+ * (in which case the method Laurent_series needs to be implemented).
+ *
+ * Returns false if this is not the case 
+ * (and the class has an implementation of series_coeff_impl).
+ * 
+ */
+bool integration_kernel::uses_Laurent_series() const
+{
+       return false;
+}
+
+/**
+ *
+ * Returns the current size of the cache.
+ *
+ */
+size_t integration_kernel::get_cache_size(void) const
+{
+       return series_vec.size();
+}
+
+/**
+ *
+ * Sets the step size by which the cache is increased.
+ *
+ */
+void integration_kernel::set_cache_step(int cache_steps) const
+{
+       cache_step_size = cache_steps;
+}
+
+/**
+ *
+ * Wrapper around series_coeff(i), converts cl_N to numeric.
+ *
+ */
+ex integration_kernel::get_series_coeff(int i) const
+{
+       return numeric(series_coeff(i));
+}
+
+/**
+ *
+ * The actual implementation for computing a numerical value for the integrand.
+ *
+ */
+ex  integration_kernel::get_numerical_value_impl(const ex & lambda, const ex & pre, int shift, int N_trunc) const
+{
+       cln::cl_N lambda_cln = ex_to<numeric>(lambda.evalf()).to_cl_N();
+       cln::cl_N pre_cln = ex_to<numeric>(pre.evalf()).to_cl_N();
+
+       cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
+
+       cln::cl_N res = 0;
+       cln::cl_N resbuf;
+       cln::cl_N subexpr;
+
+       if ( N_trunc == 0 ) {
+               // sum until precision is reached
+               bool flag_accidental_zero = false;
+
+               int N = 0;
+
+               do {
+                       resbuf = res;
+        
+                       subexpr = series_coeff(N);
+
+                       res += pre_cln * subexpr * cln::expt(lambda_cln,N-1+shift);
+
+                       flag_accidental_zero = cln::zerop(subexpr);
+
+                       N++;
+               } while ( (res != resbuf) || flag_accidental_zero );
+       }
+       else {
+               // N_trunc > 0, sum up the first N_trunc terms
+               for (int N=0; N<N_trunc; N++) {
+                       subexpr = series_coeff(N);
+
+                       res += pre_cln * subexpr * cln::expt(lambda_cln,N-1+shift);
+               }
+       }
+
+       return numeric(res);
+}
+
+void integration_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "integration_kernel()";
+}
+
+GINAC_BIND_UNARCHIVER(integration_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(basic_log_kernel, integration_kernel,
+                                    print_func<print_context>(&basic_log_kernel::do_print))
+
+basic_log_kernel::basic_log_kernel() : inherited()
+{ 
+}
+
+int basic_log_kernel::compare_same_type(const basic &other) const
+{
+       return 0;
+}
+
+cln::cl_N basic_log_kernel::series_coeff_impl(int i) const
+{
+       if ( i == 0 ) {
+               return 1;
+       }
+
+       return 0;
+}
+
+void basic_log_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "basic_log_kernel()";
+}
+
+GINAC_BIND_UNARCHIVER(basic_log_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(multiple_polylog_kernel, integration_kernel,
+                                    print_func<print_context>(&multiple_polylog_kernel::do_print))
+
+multiple_polylog_kernel::multiple_polylog_kernel() : inherited(), z(_ex1)
+{ 
+}
+
+multiple_polylog_kernel::multiple_polylog_kernel(const ex & arg_z) : inherited(), z(arg_z)
+{
+}
+
+int multiple_polylog_kernel::compare_same_type(const basic &other) const
+{
+       const multiple_polylog_kernel &o = static_cast<const multiple_polylog_kernel &>(other);
+
+       return z.compare(o.z);
+}
+
+size_t multiple_polylog_kernel::nops() const
+{
+       return 1;
+}
+
+ex multiple_polylog_kernel::op(size_t i) const
+{
+       if ( i != 0 ) {
+               throw(std::range_error("multiple_polylog_kernel::op(): out of range"));
+       }
+
+       return z;
+}
+
+ex & multiple_polylog_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       if ( i != 0 ) {
+               throw(std::range_error("multiple_polylog_kernel::let_op(): out of range"));
+       }
+
+       return z;
+}
+
+bool multiple_polylog_kernel::is_numeric(void) const
+{
+       return z.evalf().info(info_flags::numeric);
+}
+
+cln::cl_N multiple_polylog_kernel::series_coeff_impl(int i) const
+{
+       if ( i == 0 ) {
+               return 0;
+       }
+
+       return -cln::expt(ex_to<numeric>(z.evalf()).to_cl_N(),-i);
+}
+
+void multiple_polylog_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "multiple_polylog_kernel(";
+       z.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(multiple_polylog_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(ELi_kernel, integration_kernel,
+                                    print_func<print_context>(&ELi_kernel::do_print))
+
+ELi_kernel::ELi_kernel() : inherited(), n(_ex0), m(_ex0), x(_ex0), y(_ex0)
+{ 
+}
+
+ELi_kernel::ELi_kernel(const ex & arg_n, const ex & arg_m, const ex & arg_x, const ex & arg_y) : inherited(), n(arg_n), m(arg_m), x(arg_x), y(arg_y)
+{
+}
+
+int ELi_kernel::compare_same_type(const basic &other) const
+{
+       const ELi_kernel &o = static_cast<const ELi_kernel &>(other);
+       int cmpval;
+
+       cmpval = n.compare(o.n);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = m.compare(o.m);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = x.compare(o.x);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       return y.compare(o.y);
+}
+
+size_t ELi_kernel::nops() const
+{
+       return 4;
+}
+
+ex ELi_kernel::op(size_t i) const
+{
+       switch (i) {
+       case 0:
+               return n;
+       case 1:
+               return m;
+       case 2:
+               return x;
+       case 3:
+               return y;
+       default:
+               throw (std::out_of_range("ELi_kernel::op() out of range"));
+       }
+}
+
+ex & ELi_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       switch (i) {
+       case 0:
+               return n;
+       case 1:
+               return m;
+       case 2:
+               return x;
+       case 3:
+               return y;
+       default:
+               throw (std::out_of_range("ELi_kernel::let_op() out of range"));
+       }
+}
+
+bool ELi_kernel::is_numeric(void) const
+{
+       return (n.info(info_flags::nonnegint) && m.info(info_flags::numeric) && x.evalf().info(info_flags::numeric) && y.evalf().info(info_flags::numeric));
+}
+
+cln::cl_N ELi_kernel::series_coeff_impl(int i) const
+{
+       if ( i == 0 ) {
+               return 0;
+       }
+
+       int n_int = ex_to<numeric>(n).to_int();
+       int m_int = ex_to<numeric>(m).to_int();
+
+       cln::cl_N x_cln = ex_to<numeric>(x.evalf()).to_cl_N();
+       cln::cl_N y_cln = ex_to<numeric>(y.evalf()).to_cl_N();
+
+       cln::cl_N res_cln = 0;
+
+       for (int j=1; j<=i; j++) {
+               if ( (i % j) == 0 ) {
+                       int k = i/j;
+
+                       res_cln += cln::expt(x_cln,j)/cln::expt(cln::cl_I(j),n_int) * cln::expt(y_cln,k)/cln::expt(cln::cl_I(k),m_int);
+               }
+       }
+
+       return res_cln;
+}
+
+/**
+ *
+ * Returns the value of ELi_{n,m}(x,y,qbar)
+ *
+ */
+ex  ELi_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+       return get_numerical_value_impl(qbar, 1, 1, N_trunc);
+}
+
+void ELi_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "ELi_kernel(";
+       n.print(c);
+       c.s << ",";
+       m.print(c);
+       c.s << ",";
+       x.print(c);
+       c.s << ",";
+       y.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(ELi_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Ebar_kernel, integration_kernel,
+                                    print_func<print_context>(&Ebar_kernel::do_print))
+
+Ebar_kernel::Ebar_kernel() : inherited(), n(_ex0), m(_ex0), x(_ex0), y(_ex0)
+{ 
+}
+
+Ebar_kernel::Ebar_kernel(const ex & arg_n, const ex & arg_m, const ex & arg_x, const ex & arg_y) : inherited(), n(arg_n), m(arg_m), x(arg_x), y(arg_y)
+{
+}
+
+int Ebar_kernel::compare_same_type(const basic &other) const
+{
+       const Ebar_kernel &o = static_cast<const Ebar_kernel &>(other);
+       int cmpval;
+
+       cmpval = n.compare(o.n);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = m.compare(o.m);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = x.compare(o.x);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       return y.compare(o.y);
+}
+
+size_t Ebar_kernel::nops() const
+{
+       return 4;
+}
+
+ex Ebar_kernel::op(size_t i) const
+{
+       switch (i) {
+       case 0:
+               return n;
+       case 1:
+               return m;
+       case 2:
+               return x;
+       case 3:
+               return y;
+       default:
+               throw (std::out_of_range("Ebar_kernel::op() out of range"));
+       }
+}
+
+ex & Ebar_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       switch (i) {
+       case 0:
+               return n;
+       case 1:
+               return m;
+       case 2:
+               return x;
+       case 3:
+               return y;
+       default:
+               throw (std::out_of_range("Ebar_kernel::let_op() out of range"));
+       }
+}
+
+bool Ebar_kernel::is_numeric(void) const
+{
+       return (n.info(info_flags::nonnegint) && m.info(info_flags::numeric) && x.evalf().info(info_flags::numeric) && y.evalf().info(info_flags::numeric));
+}
+
+cln::cl_N Ebar_kernel::series_coeff_impl(int i) const
+{
+       if ( i == 0 ) {
+               return 0;
+       }
+
+       int n_int = ex_to<numeric>(n).to_int();
+       int m_int = ex_to<numeric>(m).to_int();
+
+       cln::cl_N x_cln = ex_to<numeric>(x.evalf()).to_cl_N();
+       cln::cl_N y_cln = ex_to<numeric>(y.evalf()).to_cl_N();
+
+       cln::cl_N res_cln = 0;
+
+       for (int j=1; j<=i; j++) {
+               if ( (i % j) == 0 ) {
+                       int k = i/j;
+
+                       res_cln += (cln::expt(x_cln,j)*cln::expt(y_cln,k)-cln::expt(cln::cl_I(-1),n_int+m_int)*cln::expt(x_cln,-j)*cln::expt(y_cln,-k))/cln::expt(cln::cl_I(j),n_int)/cln::expt(cln::cl_I(k),m_int);
+               }
+       }
+
+       return res_cln;
+}
+
+/**
+ *
+ * Returns the value of Ebar_{n,m}(x,y,qbar)
+ *
+ */
+ex  Ebar_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+       return get_numerical_value_impl(qbar, 1, 1, N_trunc);
+}
+
+void Ebar_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "Ebar_kernel(";
+       n.print(c);
+       c.s << ",";
+       m.print(c);
+       c.s << ",";
+       x.print(c);
+       c.s << ",";
+       y.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Ebar_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Kronecker_dtau_kernel, integration_kernel,
+                                    print_func<print_context>(&Kronecker_dtau_kernel::do_print))
+
+Kronecker_dtau_kernel::Kronecker_dtau_kernel() : inherited(), n(_ex0), z(_ex0), K(_ex1), C_norm(_ex1)
+{ 
+}
+
+Kronecker_dtau_kernel::Kronecker_dtau_kernel(const ex & arg_n, const ex & arg_z, const ex & arg_K, const ex & arg_C_norm) : inherited(), n(arg_n), z(arg_z), K(arg_K), C_norm(arg_C_norm)
+{
+}
+
+int Kronecker_dtau_kernel::compare_same_type(const basic &other) const
+{
+       const Kronecker_dtau_kernel &o = static_cast<const Kronecker_dtau_kernel &>(other);
+       int cmpval;
+
+       cmpval = n.compare(o.n);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = z.compare(o.z);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = K.compare(o.K);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       return C_norm.compare(o.C_norm);
+}
+
+size_t Kronecker_dtau_kernel::nops() const
+{
+       return 4;
+}
+
+ex Kronecker_dtau_kernel::op(size_t i) const
+{
+       switch (i) {
+       case 0:
+               return n;
+       case 1:
+               return z;
+       case 2:
+               return K;
+       case 3:
+               return C_norm;
+       default:
+               throw (std::out_of_range("Kronecker_dtau_kernel::op() out of range"));
+       }
+}
+
+ex & Kronecker_dtau_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       switch (i) {
+       case 0:
+               return n;
+       case 1:
+               return z;
+       case 2:
+               return K;
+       case 3:
+               return C_norm;
+       default:
+               throw (std::out_of_range("Kronecker_dtau_kernel::let_op() out of range"));
+       }
+}
+
+bool Kronecker_dtau_kernel::is_numeric(void) const
+{
+       return (n.info(info_flags::nonnegint) && z.evalf().info(info_flags::numeric) && K.info(info_flags::posint) && C_norm.evalf().info(info_flags::numeric));
+}
+
+cln::cl_N Kronecker_dtau_kernel::series_coeff_impl(int i) const
+{
+       numeric n_num = ex_to<numeric>(n);
+       int n_int = n_num.to_int();
+
+       // case n=0
+       if ( n_num == 0 ) {
+               if ( i == 0 ) {
+                       ex res = -C_norm*K;
+
+                       return ex_to<numeric>(res.evalf()).to_cl_N();
+               }
+
+               return 0;
+       }
+
+       // case n=1
+       if ( n_num == 1 ) {
+               return 0;
+       }
+
+       // case n>1
+       if ( i == 0 ) {
+               ex res = C_norm*K / factorial(n_num-2) * bernoulli(n_num)/n_num;
+
+               return ex_to<numeric>(res.evalf()).to_cl_N();
+       }
+
+       // n>1, i>0
+
+       // if K>1 the variable i needs to be a multiple of K
+       int K_int = ex_to<numeric>(K).to_int();
+
+       if ( (i % K_int) != 0 ) {
+               return 0;
+       }
+       int i_local = i/K_int;
+
+       ex w = exp(ex_to<numeric>((2*Pi*I*z).evalf()));
+       cln::cl_N w_cln = ex_to<numeric>(w).to_cl_N();
+       cln::cl_N res_cln = 0;
+       for (int j=1; j<=i_local; j++) {
+               if ( (i_local % j) == 0 ) {
+                       res_cln += (cln::expt(w_cln,j)+cln::expt(cln::cl_I(-1),n_int)*cln::expt(w_cln,-j)) * cln::expt(cln::cl_I(i_local/j),n_int-1); 
+               }
+       }
+       ex pre = -C_norm*K/factorial(n_num-2);
+
+       return ex_to<numeric>(pre.evalf()).to_cl_N() * res_cln;
+}
+
+/**
+ *
+ * Returns the value of the g^(n)(z,K*tau), where tau is given by qbar.
+ *
+ */
+ex  Kronecker_dtau_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+       numeric n_num = ex_to<numeric>(n);
+
+       if ( n_num == 0 ) {
+               return 1;
+       }
+
+       // use the direct formula here
+       if ( n_num == 1 ) {
+               ex wbar = exp(ex_to<numeric>((2*Pi*I*z).evalf()));
+               ex res = -2*Pi*I*( numeric(1,2)*(1+wbar)/(1-wbar) + Ebar_kernel(0,0,wbar,1).get_numerical_value(pow(qbar,K),N_trunc));
+
+               return ex_to<numeric>(res.evalf());
+       }
+
+       ex pre = pow(2*Pi*I,n_num)/C_norm/K/(n_num-1);
+
+       return get_numerical_value_impl(qbar, pre, 1, N_trunc);
+}
+
+void Kronecker_dtau_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "Kronecker_dtau_kernel(";
+       n.print(c);
+       c.s << ",";
+       z.print(c);
+       c.s << ",";
+       K.print(c);
+       c.s << ",";
+       C_norm.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Kronecker_dtau_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Kronecker_dz_kernel, integration_kernel,
+                                    print_func<print_context>(&Kronecker_dz_kernel::do_print))
+
+Kronecker_dz_kernel::Kronecker_dz_kernel() : inherited(), n(_ex0), z_j(_ex0), tau(_ex0), K(_ex1), C_norm(_ex1)
+{ 
+}
+
+Kronecker_dz_kernel::Kronecker_dz_kernel(const ex & arg_n, const ex & arg_z_j, const ex & arg_tau, const ex & arg_K, const ex & arg_C_norm) : inherited(), n(arg_n), z_j(arg_z_j), tau(arg_tau), K(arg_K), C_norm(arg_C_norm)
+{
+}
+
+int Kronecker_dz_kernel::compare_same_type(const basic &other) const
+{
+       const Kronecker_dz_kernel &o = static_cast<const Kronecker_dz_kernel &>(other);
+       int cmpval;
+
+       cmpval = n.compare(o.n);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = z_j.compare(o.z_j);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = tau.compare(o.tau);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = K.compare(o.K);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       return C_norm.compare(o.C_norm);
+}
+
+size_t Kronecker_dz_kernel::nops() const
+{
+       return 5;
+}
+
+ex Kronecker_dz_kernel::op(size_t i) const
+{
+       switch (i) {
+       case 0:
+               return n;
+       case 1:
+               return z_j;
+       case 2:
+               return tau;
+       case 3:
+               return K;
+       case 4:
+               return C_norm;
+       default:
+               throw (std::out_of_range("Kronecker_dz_kernel::op() out of range"));
+       }
+}
+
+ex & Kronecker_dz_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       switch (i) {
+       case 0:
+               return n;
+       case 1:
+               return z_j;
+       case 2:
+               return tau;
+       case 3:
+               return K;
+       case 4:
+               return C_norm;
+       default:
+               throw (std::out_of_range("Kronecker_dz_kernel::let_op() out of range"));
+       }
+}
+
+bool Kronecker_dz_kernel::is_numeric(void) const
+{
+       return (n.info(info_flags::nonnegint) && z_j.evalf().info(info_flags::numeric) && tau.evalf().info(info_flags::numeric) && K.info(info_flags::posint) && C_norm.evalf().info(info_flags::numeric));
+}
+
+cln::cl_N Kronecker_dz_kernel::series_coeff_impl(int i) const
+{
+       numeric n_num = ex_to<numeric>(n);
+       int n_int = n_num.to_int();
+
+       ex w_j_inv = exp(ex_to<numeric>((-2*Pi*I*z_j).evalf()));
+       cln::cl_N w_j_inv_cln = ex_to<numeric>(w_j_inv).to_cl_N();
+
+       ex qbar = exp(ex_to<numeric>((2*Pi*I*K*tau).evalf()));
+
+       // case n=0
+       if ( n_num == 0 ) {
+               return 0;
+       }
+
+       // case n=1
+       if ( n_num == 1 ) {
+               if ( i == 1 ) {
+                       return ex_to<numeric>((C_norm * 2*Pi*I).evalf()).to_cl_N();
+               }
+
+               return 0;
+       }
+
+       // case n=2
+       if ( n_num == 2 ) {
+               if ( ex_to<numeric>(z_j.evalf()).is_zero() ) {
+                       if ( i == 0 ) {
+                               return ex_to<numeric>((C_norm).evalf()).to_cl_N();
+                       }
+                       else if ( i == 1 ) {
+                               return 0;
+                       }
+                       else {
+                               ex res = -bernoulli(i)/numeric(i);
+                               if ( numeric(i).is_even() ) {
+                                       Ebar_kernel Ebar = Ebar_kernel( 1-i, 0, numeric(1), numeric(1) );
+                                       res += Ebar.get_numerical_value(qbar);
+                               }
+
+                               res *= -pow(2*Pi*I,i)*C_norm/factorial(i-1);
+
+                               return ex_to<numeric>(res.evalf()).to_cl_N();
+                       }
+               }
+               else {
+                       // z_j is not zero
+                       if ( i == 0 ) {
+                               return 0;
+                       }
+                       else {
+                               Li_negative my_Li_negative;
+
+                               ex res = 0;
+                               if ( i == 1 ) {
+                                       res = numeric(1,2);
+                               }
+
+                               Ebar_kernel Ebar = Ebar_kernel( 1-i, 0, w_j_inv, numeric(1) );
+
+                               res += my_Li_negative.get_numerical_value(i-1,w_j_inv) + Ebar.get_numerical_value(qbar);
+
+                               res *= -pow(2*Pi*I,i)*C_norm/factorial(i-1);
+
+                               return ex_to<numeric>(res.evalf()).to_cl_N();
+                       }
+               }
+       }
+
+       // case n>2
+       ex res = 0;
+       if ( i == 1 ) {
+               res += - bernoulli(n_num-1)/(n_num-1);
+       }
+       if ( i > 0 ) {
+               if ( ex_to<numeric>(z_j.evalf()).is_zero() ) {
+                       if ( (numeric(i)+n_num).is_even() ) {
+                               Ebar_kernel Ebar = Ebar_kernel( 1-i, 2-n_num, numeric(1), numeric(1) );
+
+                               res += pow(2*Pi*I,i-1)/factorial(i-1) * Ebar.get_numerical_value(qbar);
+                       }
+               }
+               else {
+                       // z_j is not zero
+                       Ebar_kernel Ebar = Ebar_kernel( 1-i, 2-n_num, w_j_inv, numeric(1) );
+
+                       res += pow(2*Pi*I,i-1)/factorial(i-1) * Ebar.get_numerical_value(qbar);
+               }
+       }
+
+       res *= - C_norm * 2*Pi*I/factorial(n_num-2);
+
+       return ex_to<numeric>(res.evalf()).to_cl_N();
+}
+
+/**
+ *
+ * Returns the value of the g^(n-1)(z-z_j,K*tau).
+ *
+ */
+ex  Kronecker_dz_kernel::get_numerical_value(const ex & z, int N_trunc) const
+{
+       numeric n_num = ex_to<numeric>(n);
+
+       if ( n_num == 1 ) {
+               return 1;
+       }
+
+       ex pre = pow(2*Pi*I,n-2)/C_norm;
+
+       return get_numerical_value_impl(z, pre, 0, N_trunc);
+}
+
+void Kronecker_dz_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "Kronecker_dz_kernel(";
+       n.print(c);
+       c.s << ",";
+       z_j.print(c);
+       c.s << ",";
+       tau.print(c);
+       c.s << ",";
+       K.print(c);
+       c.s << ",";
+       C_norm.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Kronecker_dz_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Eisenstein_kernel, integration_kernel,
+                                    print_func<print_context>(&Eisenstein_kernel::do_print))
+
+Eisenstein_kernel::Eisenstein_kernel() : inherited(), k(_ex0), N(_ex0), a(_ex0), b(_ex0), K(_ex0), C_norm(_ex1)
+{ 
+}
+
+Eisenstein_kernel::Eisenstein_kernel(const ex & arg_k, const ex & arg_N, const ex & arg_a, const ex & arg_b, const ex & arg_K, const ex & arg_C_norm) : inherited(), k(arg_k), N(arg_N), a(arg_a), b(arg_b), K(arg_K), C_norm(arg_C_norm)
+{ 
+}
+
+int Eisenstein_kernel::compare_same_type(const basic &other) const
+{
+       const Eisenstein_kernel &o = static_cast<const Eisenstein_kernel &>(other);
+       int cmpval;
+
+       cmpval = k.compare(o.k);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = N.compare(o.N);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = a.compare(o.a);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = b.compare(o.b);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = K.compare(o.K);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       return C_norm.compare(o.C_norm);
+}
+
+/**
+ *
+ * The series method for this class returns the qbar-expansion of the modular form, 
+ * without an additional factor of C_norm/qbar.
+ *
+ * This allows for easy use in the class modular_form_kernel.
+ *
+ */
+ex Eisenstein_kernel::series(const relational & r, int order, unsigned options) const
+{
+       if ( r.rhs() != 0 ) {
+               throw (std::runtime_error("integration_kernel::series: non-zero expansion point not implemented"));
+       }
+
+       ex qbar = r.lhs();
+       ex res = q_expansion_modular_form(qbar, order);
+       res = res.series(qbar,order);
+
+       return res;
+}
+
+size_t Eisenstein_kernel::nops() const
+{
+       return 6;
+}
+
+ex Eisenstein_kernel::op(size_t i) const
+{
+       switch (i) {
+       case 0:
+               return k;
+       case 1:
+               return N;
+       case 2:
+               return a;
+       case 3:
+               return b;
+       case 4:
+               return K;
+       case 5:
+               return C_norm;
+       default:
+               throw (std::out_of_range("Eisenstein_kernel::op() out of range"));
+       }
+}
+
+ex & Eisenstein_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       switch (i) {
+       case 0:
+               return k;
+       case 1:
+               return N;
+       case 2:
+               return a;
+       case 3:
+               return b;
+       case 4:
+               return K;
+       case 5:
+               return C_norm;
+       default:
+               throw (std::out_of_range("Eisenstein_kernel::let_op() out of range"));
+       }
+}
+
+bool Eisenstein_kernel::is_numeric(void) const
+{
+       return (k.info(info_flags::nonnegint) && N.info(info_flags::posint) && a.info(info_flags::integer) && b.info(info_flags::integer) && K.info(info_flags::posint) && C_norm.evalf().info(info_flags::numeric));
+}
+
+ex Eisenstein_kernel::Laurent_series(const ex & x, int order) const
+{
+       ex res = C_norm * q_expansion_modular_form(x, order+1)/x;
+       res = res.series(x,order);
+
+       return res;
+}
+
+/**
+ *
+ * Returns the value of the modular form.
+ *
+ */
+ex  Eisenstein_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+       ex pre = numeric(1)/C_norm;
+
+       return get_numerical_value_impl(qbar, pre, 1, N_trunc);
+}
+
+bool Eisenstein_kernel::uses_Laurent_series() const
+{
+       return true;
+}
+
+ex Eisenstein_kernel::q_expansion_modular_form(const ex & q, int order) const
+{
+       numeric k_num = ex_to<numeric>(k);
+       numeric N_num = ex_to<numeric>(N);
+       numeric a_num = ex_to<numeric>(a);
+       numeric b_num = ex_to<numeric>(b);
+       numeric K_num = ex_to<numeric>(K);
+
+       if ( (k==2) && (a==1) && (b==1) ) {
+               return B_eisenstein_series(q, N_num, K_num, order);
+       }
+
+       return E_eisenstein_series(q, k_num, N_num, a_num, b_num, K_num, order);
+}
+
+void Eisenstein_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "Eisenstein_kernel(";
+       k.print(c);
+       c.s << ",";
+       N.print(c);
+       c.s << ",";
+       a.print(c);
+       c.s << ",";
+       b.print(c);
+       c.s << ",";
+       K.print(c);
+       c.s << ",";
+       C_norm.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Eisenstein_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Eisenstein_h_kernel, integration_kernel,
+                                    print_func<print_context>(&Eisenstein_h_kernel::do_print))
+
+Eisenstein_h_kernel::Eisenstein_h_kernel() : inherited(), k(_ex0), N(_ex0), r(_ex0), s(_ex0), C_norm(_ex1)
+{ 
+}
+
+Eisenstein_h_kernel::Eisenstein_h_kernel(const ex & arg_k, const ex & arg_N, const ex & arg_r, const ex & arg_s, const ex & arg_C_norm) : inherited(), k(arg_k), N(arg_N), r(arg_r), s(arg_s), C_norm(arg_C_norm)
+{ 
+}
+
+int Eisenstein_h_kernel::compare_same_type(const basic &other) const
+{
+       const Eisenstein_h_kernel &o = static_cast<const Eisenstein_h_kernel &>(other);
+       int cmpval;
+
+       cmpval = k.compare(o.k);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = N.compare(o.N);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = r.compare(o.r);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = s.compare(o.s);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       return C_norm.compare(o.C_norm);
+}
+
+/**
+ *
+ * The series method for this class returns the qbar-expansion of the modular form, 
+ * without an additional factor of C_norm/qbar.
+ *
+ * This allows for easy use in the class modular_form_kernel.
+ *
+ */
+ex Eisenstein_h_kernel::series(const relational & r, int order, unsigned options) const
+{
+       if ( r.rhs() != 0 ) {
+               throw (std::runtime_error("integration_kernel::series: non-zero expansion point not implemented"));
+       }
+
+       ex qbar = r.lhs();
+       ex res = q_expansion_modular_form(qbar, order);
+       res = res.series(qbar,order);
+
+       return res;
+}
+
+size_t Eisenstein_h_kernel::nops() const
+{
+       return 5;
+}
+
+ex Eisenstein_h_kernel::op(size_t i) const
+{
+       switch (i) {
+       case 0:
+               return k;
+       case 1:
+               return N;
+       case 2:
+               return r;
+       case 3:
+               return s;
+       case 4:
+               return C_norm;
+       default:
+               throw (std::out_of_range("Eisenstein_h_kernel::op() out of range"));
+       }
+}
+
+ex & Eisenstein_h_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       switch (i) {
+       case 0:
+               return k;
+       case 1:
+               return N;
+       case 2:
+               return r;
+       case 3:
+               return s;
+       case 4:
+               return C_norm;
+       default:
+               throw (std::out_of_range("Eisenstein_h_kernel::let_op() out of range"));
+       }
+}
+
+bool Eisenstein_h_kernel::is_numeric(void) const
+{
+       return (k.info(info_flags::nonnegint) && N.info(info_flags::posint) && r.info(info_flags::integer) && s.info(info_flags::integer) && C_norm.evalf().info(info_flags::numeric));
+}
+
+ex Eisenstein_h_kernel::Laurent_series(const ex & x, int order) const
+{
+       ex res = C_norm * q_expansion_modular_form(x, order+1)/x;
+       res = res.series(x,order);
+
+       return res;
+}
+
+/**
+ *
+ * Returns the value of the modular form.
+ *
+ */
+ex  Eisenstein_h_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+       ex pre = numeric(1)/C_norm;
+
+       return get_numerical_value_impl(qbar, pre, 1, N_trunc);
+}
+
+bool Eisenstein_h_kernel::uses_Laurent_series() const
+{
+       return true;
+}
+
+/**
+ *
+ * The constant coefficient in the Fourier expansion.
+ *
+ */
+ex Eisenstein_h_kernel::coefficient_a0(const numeric & k, const numeric & r, const numeric & s, const numeric & N) const
+{
+       if ( k == 1 ) {
+               if ( irem(s,N) != 0 ) {
+                       return numeric(1,4) - mod(s,N)/numeric(2)/N;
+               }
+               else if ( (irem(r,N)==0) && (irem(s,N)==0) ) {
+                       return 0;
+               }
+               else {
+                       return I*numeric(1,4)*cos(Pi*mod(r,N)/N)/sin(Pi*mod(r,N)/N);
+               }
+       }
+
+       // case k > 1
+       return -Bernoulli_polynomial(k,mod(s,N)/N)/numeric(2)/k;
+}
+
+/**
+ *
+ * The higher coefficients in the Fourier expansion.
+ *
+ */
+ex Eisenstein_h_kernel::coefficient_an(const numeric & n, const numeric & k, const numeric & r, const numeric & s, const numeric & N) const
+{
+       ex res = 0;
+
+       for (numeric m=1; m<=n; m++) {
+               if ( irem(n,m) == 0 ) {
+                       for (numeric c1=0; c1<N; c1++) {
+                               numeric c2 = n/m;
+                               res += pow(m,k-1)*exp(2*Pi*I/N*mod(r*c2-(s-m)*c1,N)) - pow(-m,k-1)*exp(2*Pi*I/N*mod(-r*c2+(s+m)*c1,N));
+                       }
+               }
+       }
+
+       return res/numeric(2)/pow(N,k);
+}
+
+ex Eisenstein_h_kernel::q_expansion_modular_form(const ex & q, int N_order) const
+{
+       numeric N_order_num = numeric(N_order);
+
+       numeric k_num = ex_to<numeric>(k);
+       numeric r_num = ex_to<numeric>(r);
+       numeric s_num = ex_to<numeric>(s);
+       numeric N_num = ex_to<numeric>(N);
+
+       ex res = coefficient_a0(k_num,r_num,s_num,N_num);
+
+       for (numeric i1=1; i1<N_order_num; i1++) {
+               res += coefficient_an(i1,k_num,r_num,s_num,N_num) * pow(q,i1);
+       }
+
+       res += Order(pow(q,N_order));
+       res = res.series(q,N_order);
+
+       return res;
+}
+
+void Eisenstein_h_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "Eisenstein_h_kernel(";
+       k.print(c);
+       c.s << ",";
+       N.print(c);
+       c.s << ",";
+       r.print(c);
+       c.s << ",";
+       s.print(c);
+       c.s << ",";
+       C_norm.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Eisenstein_h_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(modular_form_kernel, integration_kernel,
+                                    print_func<print_context>(&modular_form_kernel::do_print))
+
+modular_form_kernel::modular_form_kernel() : inherited(), k(_ex0), P(_ex0), C_norm(_ex1)
+{ 
+}
+
+modular_form_kernel::modular_form_kernel(const ex & arg_k, const ex & arg_P, const ex & arg_C_norm) : inherited(), k(arg_k), P(arg_P), C_norm(arg_C_norm)
+{ 
+}
+
+int modular_form_kernel::compare_same_type(const basic &other) const
+{
+       const modular_form_kernel &o = static_cast<const modular_form_kernel &>(other);
+       int cmpval;
+
+       cmpval = k.compare(o.k);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       cmpval = P.compare(o.P);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       return C_norm.compare(o.C_norm);
+}
+
+/**
+ *
+ * The series method for this class returns the qbar-expansion of the modular form, 
+ * without an additional factor of C_norm/qbar.
+ *
+ */
+ex modular_form_kernel::series(const relational & r, int order, unsigned options) const
+{
+       if ( r.rhs() != 0 ) {
+               throw (std::runtime_error("integration_kernel::series: non-zero expansion point not implemented"));
+       }
+
+       ex qbar = r.lhs();
+
+       subs_q_expansion do_subs_q_expansion(qbar, order);
+
+       ex res = do_subs_q_expansion(P).series(qbar,order);
+       res += Order(pow(qbar,order));
+       res = res.series(qbar,order);
+
+       return res;
+}
+
+size_t modular_form_kernel::nops() const
+{
+       return 3;
+}
+
+ex modular_form_kernel::op(size_t i) const
+{
+       switch (i) {
+       case 0:
+               return k;
+       case 1:
+               return P;
+       case 2:
+               return C_norm;
+       default:
+               throw (std::out_of_range("modular_form_kernel::op() out of range"));
+       }
+}
+
+ex & modular_form_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       switch (i) {
+       case 0:
+               return k;
+       case 1:
+               return P;
+       case 2:
+               return C_norm;
+       default:
+               throw (std::out_of_range("modular_form_kernel::let_op() out of range"));
+       }
+}
+
+bool modular_form_kernel::is_numeric(void) const
+{
+       bool flag = (k.info(info_flags::nonnegint) && C_norm.evalf().info(info_flags::numeric));
+       if ( !flag ) {
+               return false;
+       }
+
+       symbol qbar("qbar");
+
+       // test with a random number and random expansion
+       return series_to_poly(q_expansion_modular_form(qbar,18)).subs(qbar==numeric(1,937)).evalf().info(info_flags::numeric);
+}
+
+ex modular_form_kernel::Laurent_series(const ex & qbar, int order) const
+{
+       ex res = series_to_poly(q_expansion_modular_form(qbar,order+1));
+       res = C_norm * res/qbar;
+       res = res.series(qbar,order);
+       return res;
+}
+
+/**
+ *
+ * Returns the value of the modular form.
+ *
+ */
+ex  modular_form_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+       ex pre = numeric(1)/C_norm;
+
+       return get_numerical_value_impl(qbar, pre, 1, N_trunc);
+}
+
+bool modular_form_kernel::uses_Laurent_series() const
+{
+       return true;
+}
+
+ex modular_form_kernel::q_expansion_modular_form(const ex & q, int N_order) const
+{
+       return this->series(q==0,N_order);
+}
+
+void modular_form_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "modular_form_kernel(";
+       k.print(c);
+       c.s << ",";
+       P.print(c);
+       c.s << ",";
+       C_norm.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(modular_form_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(user_defined_kernel, integration_kernel,
+                                    print_func<print_context>(&user_defined_kernel::do_print))
+
+user_defined_kernel::user_defined_kernel() : inherited(), f(_ex0), x(_ex0)
+{ 
+}
+
+user_defined_kernel::user_defined_kernel(const ex & arg_f, const ex & arg_x) : inherited(), f(arg_f), x(arg_x)
+{ 
+}
+
+int user_defined_kernel::compare_same_type(const basic &other) const
+{
+       const user_defined_kernel &o = static_cast<const user_defined_kernel &>(other);
+       int cmpval;
+
+       cmpval = f.compare(o.f);
+       if ( cmpval) {
+               return cmpval;
+       }
+
+       return x.compare(o.x);
+}
+
+size_t user_defined_kernel::nops() const
+{
+       return 2;
+}
+
+ex user_defined_kernel::op(size_t i) const
+{
+       switch (i) {
+       case 0:
+               return f;
+       case 1:
+               return x;
+       default:
+               throw (std::out_of_range("user_defined_kernel::op() out of range"));
+       }
+}
+
+ex & user_defined_kernel::let_op(size_t i)
+{
+       ensure_if_modifiable();
+
+       switch (i) {
+       case 0:
+               return f;
+       case 1:
+               return x;
+       default:
+               throw (std::out_of_range("user_defined_kernel::let_op() out of range"));
+       }
+}
+
+bool user_defined_kernel::is_numeric(void) const
+{
+       // test with a random number
+       return f.subs(x==numeric(1,937)).evalf().info(info_flags::numeric);
+}
+
+ex user_defined_kernel::Laurent_series(const ex & x_up, int order) const
+{
+       ex res = f.series(x,order).subs(x==x_up);
+
+       return res;
+}
+
+bool user_defined_kernel::uses_Laurent_series() const
+{
+       return true;
+}
+
+void user_defined_kernel::do_print(const print_context & c, unsigned level) const
+{
+       c.s << "user_defined_kernel(";
+       f.print(c);
+       c.s << ",";
+       x.print(c);
+       c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(user_defined_kernel);
+
+} // namespace GiNaC
diff --git a/ginac/integration_kernel.h b/ginac/integration_kernel.h
new file mode 100644 (file)
index 0000000..20d6fb7
--- /dev/null
@@ -0,0 +1,669 @@
+/** @file integration_kernel.h
+ *
+ *  Interface to GiNaC's integration kernels for iterated integrals. */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef GINAC_INTEGRATION_KERNEL_H
+#define GINAC_INTEGRATION_KERNEL_H
+
+#include "basic.h"
+#include "archive.h"
+#include "numeric.h"
+#include "lst.h"
+
+#include <cln/complex.h>
+#include <vector>
+
+namespace GiNaC {
+
+ex ifactor(const numeric & n);
+bool is_discriminant_of_quadratic_number_field(const numeric & n);
+numeric kronecker_symbol(const numeric & a, const numeric & n);
+numeric primitive_dirichlet_character(const numeric & n, const numeric & a);
+numeric dirichlet_character(const numeric & n, const numeric & a, const numeric & N);
+numeric generalised_Bernoulli_number(const numeric & k, const numeric & b);
+ex Bernoulli_polynomial(const numeric & k, const ex & x);
+
+/**
+ *
+ * The base class for integration kernels for iterated integrals.
+ *
+ * This class represents the differential one-form
+ * \f[
+ *    \omega = d\lambda
+ * \f]
+ * The integration variable is a dummy variable and does not need to be specified.
+ *
+ */
+class integration_kernel : public basic
+{
+       GINAC_DECLARE_REGISTERED_CLASS(integration_kernel, basic)
+
+       // ctors
+public:
+
+       // functions overriding virtual functions from base classes
+public:
+       ex series(const relational & r, int order, unsigned options = 0) const override;
+
+protected:
+
+       // new virtual functions which can be overridden by derived classes
+public:
+       virtual bool has_trailing_zero(void) const;
+       virtual bool is_numeric(void) const;
+       virtual ex Laurent_series(const ex & x, int order) const;
+       virtual ex  get_numerical_value(const ex & lambda, int N_trunc = 0) const;
+
+protected:
+       virtual bool uses_Laurent_series() const;
+       virtual cln::cl_N series_coeff_impl(int i) const;
+
+       // non-virtual functions 
+public:
+       size_t get_cache_size(void) const;
+       void set_cache_step(int cache_steps) const;
+       ex get_series_coeff(int i) const;
+       cln::cl_N series_coeff(int i) const;
+
+protected:
+       ex  get_numerical_value_impl(const ex & lambda, const ex & pre, int shift, int N_trunc) const;
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       // cache is increased by steps of cache_step_size
+       mutable int cache_step_size;
+       // cache already computed series coefficients
+       mutable std::vector<cln::cl_N> series_vec;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(integration_kernel);
+
+/**
+ *
+ * The basic integration kernel with a logarithmic singularity at the origin.
+ *
+ * This class represents the differential one-form
+ * \f[
+ *    L_0 = \frac{d\lambda}{\lambda}
+ * \f]
+ *
+ */
+class basic_log_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(basic_log_kernel, integration_kernel)
+
+       // ctors
+public:
+
+       // functions overriding virtual functions from base classes
+public:
+
+protected:
+       cln::cl_N series_coeff_impl(int i) const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+       // friends :
+
+       // member variables :
+
+protected:
+
+};
+
+GINAC_DECLARE_UNARCHIVER(basic_log_kernel);
+
+/**
+ *
+ * The integration kernel for multiple polylogarithms.
+ *
+ * This class represents the differential one-form
+ * \f[
+ *    \omega^{\mathrm{mpl}}(z) = \frac{d\lambda}{\lambda-z}
+ * \f]
+ *
+ * For the case \f$ z=0 \f$ the class basic_log_kernel should be used.
+ *
+ */
+class multiple_polylog_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(multiple_polylog_kernel, integration_kernel)
+
+       // ctors
+public:
+       multiple_polylog_kernel(const ex & z);
+
+       // functions overriding virtual functions from base classes
+public:
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+
+protected:
+       cln::cl_N series_coeff_impl(int i) const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex z;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(multiple_polylog_kernel);
+
+/**
+ *
+ * The ELi-kernel.
+ *
+ * This class represents the differential one-form
+ * \f[
+ *    \omega^{\mathrm{ELi}}_{n;m}(x;y) = \mathrm{ELi}_{n;m}(x;y;\bar{q}) \frac{d\bar{q}}{\bar{q}}
+ * \f]
+ *
+ */
+class ELi_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(ELi_kernel, integration_kernel)
+
+       // ctors
+public:
+       ELi_kernel(const ex & n, const ex & m, const ex & x, const ex & y);
+
+       // functions overriding virtual functions from base classes
+public:
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+       ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+       cln::cl_N series_coeff_impl(int i) const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex n;
+       ex m;
+       ex x;
+       ex y;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(ELi_kernel);
+
+/**
+ *
+ * The Ebar-kernel
+ *
+ * This class represents the differential one-form
+ * \f[
+ *  \omega^{\overline{\mathrm{E}}}_{n;m}(x;y) = \overline{\mathrm{E}}_{n;m}(x;y;\bar{q}) \frac{d\bar{q}}{\bar{q}}
+ * \f]
+ *
+ */
+class Ebar_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(Ebar_kernel, integration_kernel)
+
+       // ctors
+public:
+       Ebar_kernel(const ex & n, const ex & m, const ex & x, const ex & y);
+
+       // functions overriding virtual functions from base classes
+public:
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+       ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+       cln::cl_N series_coeff_impl(int i) const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex n;
+       ex m;
+       ex x;
+       ex y;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(Ebar_kernel);
+
+/**
+ *
+ * The kernel corresponding to integrating the Kronecker coefficient function \f$ g^{(n)}(z_j,K \tau) \f$ 
+ * in \f$ \tau \f$ (or equivalently in \f$ \bar{q} \f$).
+ *
+ * This class represents the differential one-form
+ * \f[
+ *  \omega^{\mathrm{Kronecker},\tau}_{n,K}(z_j) = \frac{C_n K (n-1)}{(2\pi i)^n} g^{(n)}(z_j,K \tau) \frac{d\bar{q}}{\bar{q}}
+ * \f]
+ *
+ */
+class Kronecker_dtau_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(Kronecker_dtau_kernel, integration_kernel)
+
+       // ctors
+public:
+       Kronecker_dtau_kernel(const ex & n, const ex & z, const ex & K = numeric(1), const ex & C_norm = numeric(1));
+
+       // functions overriding virtual functions from base classes
+public:
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+       ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+       cln::cl_N series_coeff_impl(int i) const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex n;
+       ex z;
+       ex K;
+       ex C_norm;
+};
+
+GINAC_DECLARE_UNARCHIVER(Kronecker_dtau_kernel);
+
+
+/**
+ *
+ * The kernel corresponding to integrating the Kronecker coefficient function \f$ g^{(n-1)}(z-z_j, K \tau) \f$ 
+ * in \f$ z \f$.
+ *
+ * This class represents the differential one-form
+ * \f[
+ *   \omega^{\mathrm{Kronecker},z}_{n,K}(z_j,\tau) = C_n (2\pi i)^{2-n} g^{(n-1)}(z-z_j, K \tau) dz
+ * \f]
+ *
+ */
+class Kronecker_dz_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(Kronecker_dz_kernel, integration_kernel)
+
+       // ctors
+public:
+       Kronecker_dz_kernel(const ex & n, const ex & z_j, const ex & tau, const ex & K = numeric(1), const ex & C_norm = numeric(1));
+
+       // functions overriding virtual functions from base classes
+public:
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+       ex get_numerical_value(const ex & z, int N_trunc = 0) const override;
+
+protected:
+       cln::cl_N series_coeff_impl(int i) const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex n;
+       ex z_j;
+       ex tau;
+       ex K;
+       ex C_norm;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(Kronecker_dz_kernel);
+
+
+/**
+ *
+ * The kernel corresponding to the Eisenstein series \f$ E_{k,N,a,b,K}(\tau) \f$.
+ *
+ * This class represents the differential one-form
+ * \f[
+ *   \omega^{\mathrm{Eisenstein}}_{k,N,a,b,K} = C_k E_{k,N,a,b,K}(\tau) \frac{d\bar{q}_N}{\bar{q}_N}
+ * \f]
+ *
+ * The integers a and b are either one or the discriminant of a quadratic number field.
+ * This class represents Eisenstein series, which can be defined by primitive Dirichlet characters from the Kronecker symbol.
+ * This implies that the characters take the values -1,0,1, i.e. no higher roots of unity occur.
+ * The \f[ \bar{q} \f]-expansion has then rational coefficients.
+ *
+ * Ref.: W. Stein, Modular Forms: A Computational Approach, Chapter 5
+ *
+ */
+class Eisenstein_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(Eisenstein_kernel, integration_kernel)
+
+       // ctors
+public:
+       Eisenstein_kernel(const ex & k, const ex & N, const ex & a, const ex & b, const ex & K, const ex & C_norm = numeric(1));
+
+       // functions overriding virtual functions from base classes
+public:
+       ex series(const relational & r, int order, unsigned options = 0) const override;
+
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+       ex Laurent_series(const ex & x, int order) const override;
+       ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+       bool uses_Laurent_series() const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+       ex q_expansion_modular_form(const ex & q, int order) const;
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex k;
+       ex N;
+       ex a;
+       ex b;
+       ex K;
+       ex C_norm;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(Eisenstein_kernel);
+
+
+/**
+ *
+ * The kernel corresponding to the Eisenstein series \f$ h_{k,N,r,s}(\tau) \f$.
+ *
+ * This class represents the differential one-form
+ * \f[
+ *   \omega^{\mathrm{Eisenstein,h}}_{k,N,r,s} = C_k h_{k,N,r,s}(\tau) \frac{d\bar{q}_N}{\bar{q}_N}
+ * \f]
+ *
+ */
+class Eisenstein_h_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(Eisenstein_h_kernel, integration_kernel)
+
+       // ctors
+public:
+       Eisenstein_h_kernel(const ex & k, const ex & N, const ex & r, const ex & s, const ex & C_norm = numeric(1));
+
+       // functions overriding virtual functions from base classes
+public:
+       ex series(const relational & r, int order, unsigned options = 0) const override;
+
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+       ex Laurent_series(const ex & x, int order) const override;
+       ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+       bool uses_Laurent_series() const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+       ex coefficient_a0(const numeric & k, const numeric & r, const numeric & s, const numeric & N) const;
+       ex coefficient_an(const numeric & n, const numeric & k, const numeric & r, const numeric & s, const numeric & N) const;
+       ex q_expansion_modular_form(const ex & q, int order) const;
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex k;
+       ex N;
+       ex r;
+       ex s;
+       ex C_norm;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(Eisenstein_h_kernel);
+
+
+/**
+ *
+ * A kernel corresponding to a polynomial in Eisenstein series.
+ *
+ * This class represents the differential one-form
+ * \f[
+ *   \omega^{\mathrm{modular}}(P_k(\eta^{(1)}_{k_1}, \dots, \eta^{(r)}_{k_r})) = C_k P_k(\eta^{(1)}_{k_1}, \dots, \eta^{(r)}_{k_r}) \frac{d\bar{q}_N}{\bar{q}_N}.
+ * \f]
+ *
+ */
+class modular_form_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(modular_form_kernel, integration_kernel)
+
+       // ctors
+public:
+       modular_form_kernel(const ex & k, const ex & P, const ex & C_norm = numeric(1));
+
+       // functions overriding virtual functions from base classes
+public:
+       ex series(const relational & r, int order, unsigned options = 0) const override;
+
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+       ex Laurent_series(const ex & qbar, int order) const override;
+       ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+       bool uses_Laurent_series() const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+       ex q_expansion_modular_form(const ex & q, int order) const;
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex k;
+       ex P;
+       ex C_norm;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(modular_form_kernel);
+
+
+/**
+ *
+ * A user-defined integration kernel.
+ * The input is an expression \f$ f \f$, depending on a variable \f$ x \f$.
+ * It is assumed that \f$ f \f$ has a Laurent expansion around \f$ x=0 \f$ and 
+ * maximally a simple pole at \f$ x=0 \f$.
+ *
+ */
+class user_defined_kernel : public integration_kernel
+{
+       GINAC_DECLARE_REGISTERED_CLASS(user_defined_kernel, integration_kernel)
+
+       // ctors
+public:
+       user_defined_kernel(const ex & f, const ex & x);
+
+       // functions overriding virtual functions from base classes
+public:
+       size_t nops() const override;
+       ex op(size_t i) const override;
+       ex & let_op(size_t i) override;
+
+       bool is_numeric(void) const override;
+       ex Laurent_series(const ex & x, int order) const override;
+
+protected:
+       bool uses_Laurent_series() const override;
+
+       // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+       // non-virtual functions 
+public:
+
+protected:
+       void do_print(const print_context & c, unsigned level) const;
+
+        // friends :
+
+       // member variables :
+
+protected:
+       ex f;
+       ex x;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(user_defined_kernel);
+
+} // namespace GiNaC
+
+#endif // ndef GINAC_INTEGRATION_KERNEL_H
index e4164c68c1d58a7c64ca431e5de2106e9ad12ed3..73bcc700f3284b6be3389d62c7c3162a03b9c41b 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's lst. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@ template <> bool lst::info(unsigned inf) const
                return inherited::info(inf);
 }
 
+template bool container<std::list>::info(unsigned) const;
 GINAC_BIND_UNARCHIVER(lst);
 
 } // namespace GiNaC
index ff2831aa5984abf768db16d497ee6758822ada85..7b8c6f1ae8cb81f4c34d3f379e2f7f1a9a641b95 100644 (file)
@@ -3,7 +3,7 @@
  *  Definition of GiNaC's lst. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -31,6 +31,11 @@ namespace GiNaC {
 
 typedef container<std::list> lst;
 
+/** Declaration of container::reg_info for lst. */
+#ifndef _MSC_VER  // workaround error C2766: explicit specialization; 'reg_info' has already been defined
+template<> registered_class_info lst::reg_info;
+#endif
+
 /** Specialization of container::get_default_flags() for lst. */
 template<> inline unsigned lst::get_default_flags() { return status_flags::not_shareable; }
 
@@ -42,6 +47,7 @@ template<> inline char lst::get_close_delim() { return '}'; }
 
 // defined in lst.cpp
 template<> bool lst::info(unsigned inf) const;
+extern template bool container<std::list>::info(unsigned) const;
 GINAC_DECLARE_UNARCHIVER(lst);
 
 } // namespace GiNaC
index fb6750602caf1e36a34bc93eace613b24fea8323..13e7e80a71cc2463b1dbae4fd842f763bf9ef764 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of symbolic matrices */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -140,13 +140,11 @@ void matrix::read_archive(const archive_node &n, lst &sym_lst)
        m.reserve(row * col);
        // XXX: default ctor inserts a zero element, we need to erase it here.
        m.pop_back();
-       auto first = n.find_first("m");
-       auto last = n.find_last("m");
-       ++last;
-       for (auto i=first; i != last; ++i) {
+       auto range = n.find_property_range("m", "m");
+       for (auto i=range.begin; i != range.end; ++i) {
                ex e;
                n.find_ex_by_loc(i, e, sym_lst);
-               m.push_back(e);
+               m.emplace_back(e);
        }
 }
 GINAC_BIND_UNARCHIVER(matrix);
index b1ee32814b926f15d4a90b6387770394d01214ae..6be9ba4e9000c7dc7c8e8cb913a76da02061de83 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to symbolic matrices */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 
 namespace GiNaC {
 
-/** Helper template to allow initialization of matrices via an overloaded
- *  comma operator (idea stolen from Blitz++). */
-template <typename T, typename It>
-class matrix_init {
-public:
-       matrix_init(It i) : iter(i) {}
-
-       matrix_init<T, It> operator,(const T & x)
-       {
-               *iter = x;
-               return matrix_init<T, It>(++iter);
-       }
-
-       // The following specializations produce much tighter code than the
-       // general case above
-
-       matrix_init<T, It> operator,(int x)
-       {
-               *iter = T(x);
-               return matrix_init<T, It>(++iter);
-       }
-
-       matrix_init<T, It> operator,(unsigned int x)
-       {
-               *iter = T(x);
-               return matrix_init<T, It>(++iter);
-       }
-
-       matrix_init<T, It> operator,(long x)
-       {
-               *iter = T(x);
-               return matrix_init<T, It>(++iter);
-       }
-
-       matrix_init<T, It> operator,(unsigned long x)
-       {
-               *iter = T(x);
-               return matrix_init<T, It>(++iter);
-       }
-
-       matrix_init<T, It> operator,(double x)
-       {
-               *iter = T(x);
-               return matrix_init<T, It>(++iter);
-       }
-
-       matrix_init<T, It> operator,(const symbol & x)
-       {
-               *iter = T(x);
-               return matrix_init<T, It>(++iter);
-       }
-
-private:
-       matrix_init();
-       It iter;
-};
-
-
 /** Symbolic matrices. */
 class matrix : public basic
 {
@@ -102,7 +44,6 @@ public:
        matrix(unsigned r, unsigned c, const lst & l);
        matrix(std::initializer_list<std::initializer_list<ex>> l);
 
-       matrix_init<ex, exvector::iterator> operator=(const ex & x) attribute_deprecated;
 protected:
        matrix(unsigned r, unsigned c, const exvector & m2);
        matrix(unsigned r, unsigned c, exvector && m2);
@@ -177,14 +118,6 @@ protected:
 };
 GINAC_DECLARE_UNARCHIVER(matrix); 
 
-// First step of initialization of matrix with a comma-separated sequence
-// of expressions. Subsequent steps are handled by matrix_init<>::operator,().
-inline matrix_init<ex, exvector::iterator> matrix::operator=(const ex & x)
-{
-       m[0] = x;
-       return matrix_init<ex, exvector::iterator>(++m.begin());
-}
-
 // wrapper functions around member functions
 
 inline size_t nops(const matrix & m)
index 16bbc5b229ac9f21c26bcadbfacb1a26c5b6790f..a8941692ca3cbb4250e2dbe578b85a02c434943a 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's products of expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 9392cf01733963beb7a8c40854e3d57621956faf..14336d3dcbb03df925183c8b653ca8232e64079b 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's products of expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -61,7 +61,7 @@ public:
        ex imag_part() const override;
        ex evalm() const override;
        ex series(const relational & s, int order, unsigned options = 0) const override;
-       ex normal(exmap & repl, exmap & rev_lookup) const override;
+       ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
        numeric integer_content() const override;
        ex smod(const numeric &xi) const override;
        numeric max_coefficient() const override;
index f086e49235568573d19f5513dad93b930c8e79c6..5f64851a5920e52dd5a8fd7dd3e6540e9fb2c1a3 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's non-commutative products of expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index efb750f0da1bc7d714b8a3a2407abe11d2cc5d7a..d66053f8f2b6c10534941f2aaeda67d0522e16a5 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's non-commutative products of expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 5fda185981b13fdd82e800ff842db8f3ec2e1ce5..8ebac6ce0a993d8e4ffe4b24b65da607ae438408 100644 (file)
@@ -6,7 +6,7 @@
  *  computation, square-free factorization and rational function normalization. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -1428,6 +1428,7 @@ static ex gcd_pf_mul(const ex& a, const ex& b, ex* ca, ex* cb);
  *  @param cb pointer to expression that will receive the cofactor of b, or nullptr
  *  @param check_args  check whether a and b are polynomials with rational
  *         coefficients (defaults to "true")
+ *  @param options  see GiNaC::gcd_options
  *  @return the GCD as a new expression */
 ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args, unsigned options)
 {
@@ -1801,31 +1802,51 @@ static epvector sqrfree_yun(const ex &a, const symbol &x)
        ex z = w.diff(x);
        ex g = gcd(w, z);
        if (g.is_zero()) {
-               return epvector{};
+               // manifest zero or hidden zero
+               return {};
        }
        if (g.is_equal(_ex1)) {
-               return epvector{expair(a, _ex1)};
+               // w(x) and w'(x) share no factors: w(x) is square-free
+               return {expair(a, _ex1)};
        }
-       epvector results;
-       ex exponent = _ex0;
+
+       epvector factors;
+       ex i = 0;  // exponent
        do {
                w = quo(w, g, x);
                if (w.is_zero()) {
-                       return results;
+                       // hidden zero
+                       break;
                }
                z = quo(z, g, x) - w.diff(x);
-               exponent = exponent + 1;
+               i += 1;
                if (w.is_equal(x)) {
                        // shortcut for x^n with n âˆˆ â„•
-                       exponent += quo(z, w.diff(x), x);
-                       results.push_back(expair(w, exponent));
+                       i += quo(z, w.diff(x), x);
+                       factors.push_back(expair(w, i));
                        break;
                }
                g = gcd(w, z);
                if (!g.is_equal(_ex1)) {
-                       results.push_back(expair(g, exponent));
+                       factors.push_back(expair(g, i));
                }
        } while (!z.is_zero());
+
+       // correct for lost factor
+       // (being based on GCDs, Yun's algorithm only finds factors up to a unit)
+       const ex lost_factor = quo(a, mul{factors}, x);
+       if (lost_factor.is_equal(_ex1)) {
+               // trivial lost factor
+               return factors;
+       }
+       if (!factors.empty() && factors[0].coeff.is_equal(1)) {
+               // multiply factor^1 with lost_factor
+               factors[0].rest *= lost_factor;
+               return factors;
+       }
+       // no factor^1: prepend lost_factor^1 to the results
+       epvector results = {expair(lost_factor, 1)};
+       std::move(factors.begin(), factors.end(), std::back_inserter(results));
        return results;
 }
 
@@ -1891,10 +1912,14 @@ ex sqrfree(const ex &a, const lst &l)
 
        // convert the argument from something in Q[X] to something in Z[X]
        const numeric lcm = lcm_of_coefficients_denominators(a);
-       const ex tmp = multiply_lcm(a,lcm);
+       const ex tmp = multiply_lcm(a, lcm);
 
        // find the factors
        epvector factors = sqrfree_yun(tmp, x);
+       if (factors.empty()) {
+               // the polynomial was a hidden zero
+               return _ex0;
+       }
 
        // remove symbol x and proceed recursively with the remaining symbols
        args.remove_first();
@@ -1906,21 +1931,10 @@ ex sqrfree(const ex &a, const lst &l)
        }
 
        // Done with recursion, now construct the final result
-       ex result = _ex1;
-       for (auto & it : factors)
-               result *= pow(it.rest, it.coeff);
-
-       // Yun's algorithm does not account for constant factors.  (For univariate
-       // polynomials it works only in the monic case.)  We can correct this by
-       // inserting what has been lost back into the result.  For completeness
-       // we'll also have to recurse down that factor in the remaining variables.
-       if (args.nops()>0)
-               result *= sqrfree(quo(tmp, result, x), args);
-       else
-               result *= quo(tmp, result, x);
+       ex result = mul(factors);
 
        // Put in the rational overall factor again and return
-       return result * lcm.inverse();
+       return result * lcm.inverse();
 }
 
 
@@ -1936,20 +1950,21 @@ ex sqrfree_parfrac(const ex & a, const symbol & x)
        // Find numerator and denominator
        ex nd = numer_denom(a);
        ex numer = nd.op(0), denom = nd.op(1);
-//clog << "numer = " << numer << ", denom = " << denom << endl;
+//std::clog << "numer = " << numer << ", denom = " << denom << std::endl;
 
        // Convert N(x)/D(x) -> Q(x) + R(x)/D(x), so degree(R) < degree(D)
        ex red_poly = quo(numer, denom, x), red_numer = rem(numer, denom, x).expand();
-//clog << "red_poly = " << red_poly << ", red_numer = " << red_numer << endl;
+//std::clog << "red_poly = " << red_poly << ", red_numer = " << red_numer << std::endl;
 
        // Factorize denominator and compute cofactors
        epvector yun = sqrfree_yun(denom, x);
-       size_t yun_max_exponent = yun.empty() ? 0 : ex_to<numeric>(yun.back().coeff).to_int();
        exvector factor, cofac;
+       size_t dim = 0;
        for (size_t i=0; i<yun.size(); i++) {
                numeric i_exponent = ex_to<numeric>(yun[i].coeff);
                for (size_t j=0; j<i_exponent; j++) {
                        factor.push_back(pow(yun[i].rest, j+1));
+                       dim += degree(yun[i].rest, x);
                        ex prod = _ex1;
                        for (size_t k=0; k<yun.size(); k++) {
                                if (yun[k].coeff == i_exponent)
@@ -1960,34 +1975,58 @@ ex sqrfree_parfrac(const ex & a, const symbol & x)
                        cofac.push_back(prod.expand());
                }
        }
-       size_t num_factors = factor.size();
-//clog << "factors  : " << exprseq(factor) << endl;
-//clog << "cofactors: " << exprseq(cofac) << endl;
-
-       // Construct coefficient matrix for decomposition
-       int max_denom_deg = denom.degree(x);
-       matrix sys(max_denom_deg + 1, num_factors);
-       matrix rhs(max_denom_deg + 1, 1);
-       for (int i=0; i<=max_denom_deg; i++) {
-               for (size_t j=0; j<num_factors; j++)
-                       sys(i, j) = cofac[j].coeff(x, i);
-               rhs(i, 0) = red_numer.coeff(x, i);
-       }
-//clog << "coeffs: " << sys << endl;
-//clog << "rhs   : " << rhs << endl;
-
-       // Solve resulting linear system
-       matrix vars(num_factors, 1);
-       for (size_t i=0; i<num_factors; i++)
-               vars(i, 0) = symbol();
+//std::clog << "factors  : " << exprseq(factor) << std::endl;
+//std::clog << "cofactors: " << exprseq(cofac) << std::endl;
+
+       // Construct linear system for decomposition
+       matrix sys(dim, dim);
+       matrix rhs(dim, 1);
+       matrix vars(dim, 1);
+       for (size_t i=0, n=0, f=0; i<yun.size(); i++) {
+               size_t i_expo = to_int(ex_to<numeric>(yun[i].coeff));
+               for (size_t j=0; j<i_expo; j++) {
+                       for (size_t k=0; k<size_t(degree(yun[i].rest, x)); k++) {
+                               GINAC_ASSERT(n < dim  &&  f < factor.size());
+
+                               // column n of coefficient matrix
+                               for (size_t r=0; r+k<dim; r++) {
+                                       sys(r+k, n) = cofac[f].coeff(x, r);
+                               }
+
+                               // element n of right hand side vector
+                               rhs(n, 0) = red_numer.coeff(x, n);
+
+                               // element n of free variables vector
+                               vars(n, 0) = symbol();
+
+                               n++;
+                       }
+                       f++;
+               }
+       }
+//std::clog << "coeffs: " << sys << std::endl;
+//std::clog << "rhs   : " << rhs << std::endl;
+
+       // Solve resulting linear system and sum up decomposed fractions
        matrix sol = sys.solve(vars, rhs);
+//std::clog << "sol   : " << sol << std::endl;
+       ex sum = red_poly;
+       for (size_t i=0, n=0, f=0; i<yun.size(); i++) {
+               size_t i_expo = to_int(ex_to<numeric>(yun[i].coeff));
+               for (size_t j=0; j<i_expo; j++) {
+                       ex frac_numer = 0;
+                       for (size_t k=0; k<size_t(degree(yun[i].rest, x)); k++) {
+                               GINAC_ASSERT(n < dim  &&  f < factor.size());
+                               frac_numer += sol(n, 0) * pow(x, k);
+                               n++;
+                       }
+                       sum += frac_numer / factor[f];
 
-       // Sum up decomposed fractions
-       ex sum = 0;
-       for (size_t i=0; i<num_factors; i++)
-               sum += sol(i, 0) / factor[i];
+                       f++;
+               }
+       }
 
-       return red_poly + sum;
+       return sum;
 }
 
 
@@ -2007,8 +2046,36 @@ ex sqrfree_parfrac(const ex & a, const symbol & x)
 /** Create a symbol for replacing the expression "e" (or return a previously
  *  assigned symbol). The symbol and expression are appended to repl, for
  *  a later application of subs().
+ *  An entry in the replacement table repl can be changed in some cases.
+ *  If it was altered, we need to provide the modifier for the previously build expressions.
+ *  The modifier is an (ordered) list, because those substitutions need to be done in the
+ *  incremental order.
+ *  As an example let us consider a rationalisation of the expression
+ *      e = exp(2*x)*cos(exp(2*x)+1)*exp(x)
+ *  The first factor GiNaC denotes by something like symbol1 and will record:
+ *      e =symbol1*cos(symbol1 + 1)*exp(x)
+ *      repl = {symbol1 : exp(2*x)}
+ *  Similarly, the second factor would be denoted as symbol2 and we will have
+ *      e =symbol1*symbol2*exp(x)
+ *      repl = {symbol1 : exp(2*x), symbol2 : cos(symbol1 + 1)}
+ *  Denoting the third term as symbol3 GiNaC is willing to re-think exp(2*x) as
+ *  symbol3^2 rather than just symbol1. Here are two issues:
+ *  1) The replacement "symbol1 -> symbol3^2" in the previous part of the expression
+ *      needs to be done outside of the present routine;
+ *  2) The pair "symbol1 : exp(2*x)" shall be deleted from the replacement table repl.
+ *      However, this will create illegal substitution "symbol2 : cos(symbol1 + 1)" with
+ *      undefined symbol1.
+ *  These both problems are mitigated through the additions of the record
+ *  "symbol1==symbol3^2" to the list modifier. Changed length of the modifier signals
+ *  to the calling code that the previous portion of the expression needs to be
+ *  altered (it solves 1). Thus GiNaC can record now
+ *      e =symbol3^2*symbol2*symbol3
+ *      repl = {symbol2 : cos(symbol1 + 1), symbol3 : exp(x)}
+ *      modifier = {symbol1==symbol3^2}
+ *  Then, doing the backward substitutions the list modifier will be used to restore
+ *  such iterative substitutions in the right way (this solves 2).
  *  @see ex::normal */
-static ex replace_with_symbol(const ex & e, exmap & repl, exmap & rev_lookup)
+static ex replace_with_symbol(const ex & e, exmap & repl, exmap & rev_lookup, lst & modifier)
 {
        // Since the repl contains replaced expressions we should search for them
        ex e_replaced = e.subs(repl, subs_options::no_pattern);
@@ -2018,6 +2085,95 @@ static ex replace_with_symbol(const ex & e, exmap & repl, exmap & rev_lookup)
        if (it != rev_lookup.end())
                return it->second;
 
+       // The expression can be the base of substituted power, which requires a more careful search
+       if (! is_a<numeric>(e_replaced))
+               for (auto & it : repl)
+                       if (is_a<power>(it.second) && e_replaced.is_equal(it.second.op(0))) {
+                               ex degree = pow(it.second.op(1), _ex_1);
+                               if (is_a<numeric>(degree) && ex_to<numeric>(degree).is_integer())
+                                       return pow(it.first, degree);
+                       }
+
+       // We treat powers and the exponent functions differently because
+       // they can be rationalised more efficiently
+       if (is_a<function>(e_replaced) && is_ex_the_function(e_replaced, exp)) {
+               for (auto & it : repl) {
+                       if (is_a<function>(it.second) && is_ex_the_function(it.second, exp)) {
+                               ex ratio = normal(e_replaced.op(0) / it.second.op(0));
+                               if (is_a<numeric>(ratio) && ex_to<numeric>(ratio).is_rational()) {
+                                       // Different exponents can be treated as powers of the same basic equation
+                                       if (ex_to<numeric>(ratio).is_integer()) {
+                                               // If ratio is an integer then this is simply the power of the existing symbol.
+                                               // std::clog << e_replaced << " is a " << ratio << " power of " << it.first << std::endl;
+                                               return dynallocate<power>(it.first, ratio);
+                                       } else {
+                                               // otherwise we need to give the replacement pattern to change
+                                               // the previous expression...
+                                               ex es = dynallocate<symbol>();
+                                               ex Num = numer(ratio);
+                                               modifier.append(it.first == power(es, denom(ratio)));
+                                               // std::clog << e_replaced << " is power " << Num << " and "
+                                               //                << it.first << " is power " << denom(ratio) << " of the common base "
+                                               //                << exp(e_replaced.op(0)/Num) << std::endl;
+                                               // ... and  modify the replacement tables
+                                               rev_lookup.erase(it.second);
+                                               rev_lookup.insert({exp(e_replaced.op(0)/Num), es});
+                                               repl.erase(it.first);
+                                               repl.insert({es, exp(e_replaced.op(0)/Num)});
+                                               return dynallocate<power>(es, Num);
+                                       }
+                               }
+                       }
+               }
+       } else if (is_a<power>(e_replaced) && !is_a<numeric>(e_replaced.op(0)) // We do not replace simple monomials like x^3 or sqrt(2)
+                  && ! (is_a<symbol>(e_replaced.op(0))
+                      && is_a<numeric>(e_replaced.op(1)) && ex_to<numeric>(e_replaced.op(1)).is_integer())) {
+               for (auto & it : repl) {
+                       if (e_replaced.op(0).is_equal(it.second) // The base is an allocated symbol or base of power
+                           || (is_a<power>(it.second) && e_replaced.op(0).is_equal(it.second.op(0)))) {
+                               ex ratio; // We bind together two above cases
+                               if (is_a<power>(it.second))
+                                       ratio = normal(e_replaced.op(1) / it.second.op(1));
+                               else
+                                       ratio = e_replaced.op(1);
+                               if (is_a<numeric>(ratio) && ex_to<numeric>(ratio).is_rational())  {
+                                       // Different powers can be treated as powers of the same basic equation
+                                       if (ex_to<numeric>(ratio).is_integer()) {
+                                               // If ratio is an integer then this is simply the power of the existing symbol.
+                                               //std::clog << e_replaced << " is a " << ratio << " power of " << it.first << std::endl;
+                                               return dynallocate<power>(it.first, ratio);
+                                       } else {
+                                               // otherwise we need to give the replacement pattern to change
+                                               // the previous expression...
+                                               ex es = dynallocate<symbol>();
+                                               ex Num = numer(ratio);
+                                               modifier.append(it.first == power(es, denom(ratio)));
+                                               //std::clog << e_replaced << " is power " << Num << " and "
+                                               //                << it.first << " is power " << denom(ratio) << " of the common base "
+                                               //                << pow(e_replaced.op(0), e_replaced.op(1)/Num) << std::endl;
+                                               // ... and  modify the replacement tables
+                                               rev_lookup.erase(it.second);
+                                               rev_lookup.insert({pow(e_replaced.op(0), e_replaced.op(1)/Num), es});
+                                               repl.erase(it.first);
+                                               repl.insert({es, pow(e_replaced.op(0), e_replaced.op(1)/Num)});
+                                               return dynallocate<power>(es, Num);
+                                       }
+                               }
+                       }
+               }
+               // There is no existing substitution, thus we are creating a new one.
+               // This needs to be done separately to treat possible occurrences of
+               // b = e_replaced.op(0) elsewhere in the expression as pow(b, 1).
+               ex degree = pow(e_replaced.op(1), _ex_1);
+               if (is_a<numeric>(degree) && ex_to<numeric>(degree).is_integer()) {
+                       ex es = dynallocate<symbol>();
+                       modifier.append(e_replaced.op(0) == power(es, degree));
+                       repl.insert({es, e_replaced});
+                       rev_lookup.insert({e_replaced, es});
+                       return es;
+               }
+       }
+
        // Otherwise create new symbol and add to list, taking care that the
        // replacement expression doesn't itself contain symbols from repl,
        // because subs() is not recursive
@@ -2059,19 +2215,31 @@ struct normal_map_function : public map_function {
 /** Default implementation of ex::normal(). It normalizes the children and
  *  replaces the object with a temporary symbol.
  *  @see ex::normal */
-ex basic::normal(exmap & repl, exmap & rev_lookup) const
+ex basic::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
 {
        if (nops() == 0)
-               return dynallocate<lst>({replace_with_symbol(*this, repl, rev_lookup), _ex1});
+               return dynallocate<lst>({replace_with_symbol(*this, repl, rev_lookup, modifier), _ex1});
 
        normal_map_function map_normal;
-       return dynallocate<lst>({replace_with_symbol(map(map_normal), repl, rev_lookup), _ex1});
+       size_t nmod = modifier.nops(); // To watch new modifiers to the replacement list
+       ex result = replace_with_symbol(map(map_normal), repl, rev_lookup, modifier);
+       for (size_t imod = nmod; imod < modifier.nops(); ++imod) {
+               exmap this_repl;
+               this_repl.insert(std::make_pair(modifier.op(imod).op(0), modifier.op(imod).op(1)));
+               result = result.subs(this_repl, subs_options::no_pattern);
+       }
+
+       // Sometimes we may obtain negative powers, they need to be placed to denominator
+       if (is_a<power>(result) && result.op(1).info(info_flags::negative))
+               return dynallocate<lst>({_ex1, power(result.op(0), -result.op(1))});
+       else
+               return dynallocate<lst>({result, _ex1});
 }
 
 
 /** Implementation of ex::normal() for symbols. This returns the unmodified symbol.
  *  @see ex::normal */
-ex symbol::normal(exmap & repl, exmap & rev_lookup) const
+ex symbol::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
 {
        return dynallocate<lst>({*this, _ex1});
 }
@@ -2081,19 +2249,19 @@ ex symbol::normal(exmap & repl, exmap & rev_lookup) const
  *  into re+I*im and replaces I and non-rational real numbers with a temporary
  *  symbol.
  *  @see ex::normal */
-ex numeric::normal(exmap & repl, exmap & rev_lookup) const
+ex numeric::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
 {
        numeric num = numer();
        ex numex = num;
 
        if (num.is_real()) {
                if (!num.is_integer())
-                       numex = replace_with_symbol(numex, repl, rev_lookup);
+                       numex = replace_with_symbol(numex, repl, rev_lookup, modifier);
        } else { // complex
                numeric re = num.real(), im = num.imag();
-               ex re_ex = re.is_rational() ? re : replace_with_symbol(re, repl, rev_lookup);
-               ex im_ex = im.is_rational() ? im : replace_with_symbol(im, repl, rev_lookup);
-               numex = re_ex + im_ex * replace_with_symbol(I, repl, rev_lookup);
+               ex re_ex = re.is_rational() ? re : replace_with_symbol(re, repl, rev_lookup, modifier);
+               ex im_ex = im.is_rational() ? im : replace_with_symbol(im, repl, rev_lookup, modifier);
+               numex = re_ex + im_ex * replace_with_symbol(I, repl, rev_lookup, modifier);
        }
 
        // Denominator is always a real integer (see numeric::denom())
@@ -2165,18 +2333,19 @@ static ex frac_cancel(const ex &n, const ex &d)
 /** Implementation of ex::normal() for a sum. It expands terms and performs
  *  fractional addition.
  *  @see ex::normal */
-ex add::normal(exmap & repl, exmap & rev_lookup) const
+ex add::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
 {
        // Normalize children and split each one into numerator and denominator
        exvector nums, dens;
        nums.reserve(seq.size()+1);
        dens.reserve(seq.size()+1);
+       size_t nmod = modifier.nops(); // To watch new modifiers to the replacement list
        for (auto & it : seq) {
-               ex n = ex_to<basic>(recombine_pair_to_ex(it)).normal(repl, rev_lookup);
+               ex n = ex_to<basic>(recombine_pair_to_ex(it)).normal(repl, rev_lookup, modifier);
                nums.push_back(n.op(0));
                dens.push_back(n.op(1));
        }
-       ex n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup);
+       ex n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup, modifier);
        nums.push_back(n.op(0));
        dens.push_back(n.op(1));
        GINAC_ASSERT(nums.size() == dens.size());
@@ -2189,6 +2358,18 @@ ex add::normal(exmap & repl, exmap & rev_lookup) const
        auto num_it = nums.begin(), num_itend = nums.end();
        auto den_it = dens.begin(), den_itend = dens.end();
 //std::clog << " num = " << *num_it << ", den = " << *den_it << std::endl;
+       for (size_t imod = nmod; imod < modifier.nops(); ++imod) {
+               while (num_it != num_itend) {
+                       *num_it = num_it->subs(modifier.op(imod), subs_options::no_pattern);
+                       ++num_it;
+                       *den_it = den_it->subs(modifier.op(imod), subs_options::no_pattern);
+                       ++den_it;
+               }
+               // Reset iterators for the next round
+               num_it = nums.begin();
+               den_it = dens.begin();
+       }
+
        ex num = *num_it++, den = *den_it++;
        while (num_it != num_itend) {
 //std::clog << " num = " << *num_it << ", den = " << *den_it << std::endl;
@@ -2217,35 +2398,55 @@ ex add::normal(exmap & repl, exmap & rev_lookup) const
 /** Implementation of ex::normal() for a product. It cancels common factors
  *  from fractions.
  *  @see ex::normal() */
-ex mul::normal(exmap & repl, exmap & rev_lookup) const
+ex mul::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
 {
        // Normalize children, separate into numerator and denominator
        exvector num; num.reserve(seq.size());
        exvector den; den.reserve(seq.size());
        ex n;
+       size_t nmod = modifier.nops(); // To watch new modifiers to the replacement list
        for (auto & it : seq) {
-               n = ex_to<basic>(recombine_pair_to_ex(it)).normal(repl, rev_lookup);
+               n = ex_to<basic>(recombine_pair_to_ex(it)).normal(repl, rev_lookup, modifier);
                num.push_back(n.op(0));
                den.push_back(n.op(1));
        }
-       n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup);
+       n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup, modifier);
        num.push_back(n.op(0));
        den.push_back(n.op(1));
+       auto num_it = num.begin(), num_itend = num.end();
+       auto den_it = den.begin();
+       for (size_t imod = nmod; imod < modifier.nops(); ++imod) {
+               while (num_it != num_itend) {
+                       *num_it = num_it->subs(modifier.op(imod), subs_options::no_pattern);
+                       ++num_it;
+                       *den_it = den_it->subs(modifier.op(imod), subs_options::no_pattern);
+                       ++den_it;
+               }
+               num_it = num.begin();
+               den_it = den.begin();
+       }
 
        // Perform fraction cancellation
        return frac_cancel(dynallocate<mul>(num), dynallocate<mul>(den));
 }
 
 
-/** Implementation of ex::normal([B) for powers. It normalizes the basis,
+/** 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(exmap & repl, exmap & rev_lookup) const
+ex power::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
 {
        // Normalize basis and exponent (exponent gets reassembled)
-       ex n_basis = ex_to<basic>(basis).normal(repl, rev_lookup);
-       ex n_exponent = ex_to<basic>(exponent).normal(repl, rev_lookup);
+       size_t nmod = modifier.nops(); // To watch new modifiers to the replacement list
+       ex n_basis = ex_to<basic>(basis).normal(repl, rev_lookup, modifier);
+       for (size_t imod = nmod; imod < modifier.nops(); ++imod)
+               n_basis = n_basis.subs(modifier.op(imod), subs_options::no_pattern);
+
+       nmod = modifier.nops();
+       ex n_exponent = ex_to<basic>(exponent).normal(repl, rev_lookup, modifier);
+       for (size_t imod = nmod; imod < modifier.nops(); ++imod)
+               n_exponent = n_exponent.subs(modifier.op(imod), subs_options::no_pattern);
        n_exponent = n_exponent.op(0) / n_exponent.op(1);
 
        if (n_exponent.info(info_flags::integer)) {
@@ -2266,32 +2467,32 @@ ex power::normal(exmap & repl, exmap & rev_lookup) const
                if (n_exponent.info(info_flags::positive)) {
 
                        // (a/b)^x -> {sym((a/b)^x), 1}
-                       return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup), _ex1});
+                       return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup, modifier), _ex1});
 
                } else if (n_exponent.info(info_flags::negative)) {
 
                        if (n_basis.op(1).is_equal(_ex1)) {
 
                                // a^-x -> {1, sym(a^x)}
-                               return dynallocate<lst>({_ex1, replace_with_symbol(pow(n_basis.op(0), -n_exponent), repl, rev_lookup)});
+                               return dynallocate<lst>({_ex1, replace_with_symbol(pow(n_basis.op(0), -n_exponent), repl, rev_lookup, modifier)});
 
                        } else {
 
                                // (a/b)^-x -> {sym((b/a)^x), 1}
-                               return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(1) / n_basis.op(0), -n_exponent), repl, rev_lookup), _ex1});
+                               return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(1) / n_basis.op(0), -n_exponent), repl, rev_lookup, modifier), _ex1});
                        }
                }
        }
 
        // (a/b)^x -> {sym((a/b)^x, 1}
-       return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup), _ex1});
+       return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup, modifier), _ex1});
 }
 
 
 /** Implementation of ex::normal() for pseries. It normalizes each coefficient
  *  and replaces the series by a temporary symbol.
  *  @see ex::normal */
-ex pseries::normal(exmap & repl, exmap & rev_lookup) const
+ex pseries::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
 {
        epvector newseq;
        for (auto & it : seq) {
@@ -2300,7 +2501,7 @@ ex pseries::normal(exmap & repl, exmap & rev_lookup) const
                        newseq.push_back(expair(restexp, it.coeff));
        }
        ex n = pseries(relational(var,point), std::move(newseq));
-       return dynallocate<lst>({replace_with_symbol(n, repl, rev_lookup), _ex1});
+       return dynallocate<lst>({replace_with_symbol(n, repl, rev_lookup, modifier), _ex1});
 }
 
 
@@ -2318,13 +2519,17 @@ ex pseries::normal(exmap & repl, exmap & rev_lookup) const
 ex ex::normal() const
 {
        exmap repl, rev_lookup;
+       lst modifier;
 
-       ex e = bp->normal(repl, rev_lookup);
+       ex e = bp->normal(repl, rev_lookup, modifier);
        GINAC_ASSERT(is_a<lst>(e));
 
        // Re-insert replaced symbols
-       if (!repl.empty())
+       if (!repl.empty()) {
+               for(size_t i=0; i < modifier.nops(); ++i)
+                       e = e.subs(modifier.op(i), subs_options::no_pattern);
                e = e.subs(repl, subs_options::no_pattern);
+       }
 
        // Convert {numerator, denominator} form back to fraction
        return e.op(0) / e.op(1);
@@ -2339,15 +2544,20 @@ ex ex::normal() const
 ex ex::numer() const
 {
        exmap repl, rev_lookup;
+       lst modifier;
 
-       ex e = bp->normal(repl, rev_lookup);
+       ex e = bp->normal(repl, rev_lookup, modifier);
        GINAC_ASSERT(is_a<lst>(e));
 
        // Re-insert replaced symbols
        if (repl.empty())
                return e.op(0);
-       else
+       else {
+               for(size_t i=0; i < modifier.nops(); ++i)
+                       e = e.subs(modifier.op(i), subs_options::no_pattern);
+
                return e.op(0).subs(repl, subs_options::no_pattern);
+       }
 }
 
 /** Get denominator of an expression. If the expression is not of the normal
@@ -2359,15 +2569,20 @@ ex ex::numer() const
 ex ex::denom() const
 {
        exmap repl, rev_lookup;
+       lst modifier;
 
-       ex e = bp->normal(repl, rev_lookup);
+       ex e = bp->normal(repl, rev_lookup, modifier);
        GINAC_ASSERT(is_a<lst>(e));
 
        // Re-insert replaced symbols
        if (repl.empty())
                return e.op(1);
-       else
+       else {
+               for(size_t i=0; i < modifier.nops(); ++i)
+                       e = e.subs(modifier.op(i), subs_options::no_pattern);
+
                return e.op(1).subs(repl, subs_options::no_pattern);
+       }
 }
 
 /** Get numerator and denominator of an expression. If the expression is not
@@ -2379,15 +2594,20 @@ ex ex::denom() const
 ex ex::numer_denom() const
 {
        exmap repl, rev_lookup;
+       lst modifier;
 
-       ex e = bp->normal(repl, rev_lookup);
+       ex e = bp->normal(repl, rev_lookup, modifier);
        GINAC_ASSERT(is_a<lst>(e));
 
        // Re-insert replaced symbols
        if (repl.empty())
                return e;
-       else
+       else {
+               for(size_t i=0; i < modifier.nops(); ++i)
+                       e = e.subs(modifier.op(i), subs_options::no_pattern);
+
                return e.subs(repl, subs_options::no_pattern);
+       }
 }
 
 
@@ -2494,7 +2714,7 @@ ex power::to_rational(exmap & repl) const
 ex power::to_polynomial(exmap & repl) const
 {
        if (exponent.info(info_flags::posint))
-               return pow(basis.to_rational(repl), exponent);
+               return pow(basis.to_polynomial(repl), exponent);
        else if (exponent.info(info_flags::negint))
        {
                ex basis_pref = collect_common_factors(basis);
@@ -2565,7 +2785,7 @@ static ex find_common_factor(const ex & e, ex & factor, exmap & repl)
                                x *= f;
                        }
 
-                       if (i == 0)
+                       if (gc.is_zero())
                                gc = x;
                        else
                                gc = gcd(gc, x);
@@ -2576,6 +2796,9 @@ static ex find_common_factor(const ex & e, ex & factor, exmap & repl)
                if (gc.is_equal(_ex1))
                        return e;
 
+               if (gc.is_zero())
+                       return _ex0;
+
                // The GCD is the factor we pull out
                factor *= gc;
 
index eb579d6b4cb5aa3ebf181b02cd9f56e0269c0387..ef02ae8bc4c0b1380cf811c15b37698883d5165b 100644 (file)
@@ -6,7 +6,7 @@
  *  computation, square-free factorization and rational function normalization. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 4cfd7e4a6949da20f6470d23e6753c356e4f57e9..900cac17438460544878c9ee4ff4996fae5df8dc 100644 (file)
@@ -7,7 +7,7 @@
  *  of special functions or implement the interface to the bignum package. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include "numeric.h"
 #include "ex.h"
 #include "operators.h"
@@ -141,6 +137,17 @@ numeric::numeric(unsigned long i)
        setflag(status_flags::evaluated | status_flags::expanded);
 }
 
+numeric::numeric(long long i)
+{
+       value = cln::cl_I(i);
+       setflag(status_flags::evaluated | status_flags::expanded);
+}
+
+numeric::numeric(unsigned long long i)
+{
+       value = cln::cl_I(i);
+       setflag(status_flags::evaluated | status_flags::expanded);
+}
 
 /** Constructor for rational numerics a/b.
  *
@@ -466,7 +473,7 @@ static inline bool coerce(T1& dst, const T2& arg);
 /** 
  * @brief Check if CLN integer can be converted into int
  *
- * @sa http://www.ginac.de/pipermail/cln-list/2006-October/000248.html
+ * @sa https://www.ginac.de/pipermail/cln-list/2006-October/000248.html
  */
 template<>
 inline bool coerce<int, cln::cl_I>(int& dst, const cln::cl_I& arg)
@@ -2131,8 +2138,10 @@ const numeric doublefactorial(const numeric &n)
 
 /** The Binomial coefficients.  It computes the binomial coefficients.  For
  *  integer n and k and positive n this is the number of ways of choosing k
- *  objects from n distinct objects.  If n is negative, the formula
- *  binomial(n,k) == (-1)^k*binomial(k-n-1,k) is used to compute the result. */
+ *  objects from n distinct objects.  If n is a negative integer, the formula
+ *  binomial(n,k) == (-1)^k*binomial(k-n-1,k) (if k>=0)
+ *  binomial(n,k) == (-1)^(n-k)*binomial(-k-1,n-k) (otherwise)
+ *  is used to compute the result. */
 const numeric binomial(const numeric &n, const numeric &k)
 {
        if (n.is_integer() && k.is_integer()) {
@@ -2142,7 +2151,10 @@ const numeric binomial(const numeric &n, const numeric &k)
                        else
                                return *_num0_p;
                } else {
-                       return _num_1_p->power(k)*binomial(k-n-(*_num1_p),k);
+                       if (k.is_nonneg_integer())
+                               return _num_1_p->power(k)*binomial(k-n-(*_num1_p), k);
+                       else
+                               return _num_1_p->power(n-k)*binomial(-k-(*_num1_p), n-k);
                }
        }
        
index da41bd32fb3b5ec1cae346fd0c802a8ea9b4805d..6aff6b35a26d32b5ac9c5d96add65620997bb896 100644 (file)
@@ -3,7 +3,7 @@
  *  Makes the interface to the underlying bignum package available. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -90,6 +90,8 @@ public:
        numeric(unsigned int i);
        numeric(long i);
        numeric(unsigned long i);
+       numeric(long long i);
+       numeric(unsigned long long i);
        numeric(long numer, long denom);
        numeric(double d);
        numeric(const char *);
@@ -106,7 +108,7 @@ public:
        ex eval() const override;
        ex evalf() const override;
        ex subs(const exmap & m, unsigned options = 0) const override { return subs_one_level(m, options); } // overwrites basic::subs() for performance reasons
-       ex normal(exmap & repl, exmap & rev_lookup) const override;
+       ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
        ex to_rational(exmap & repl) const override;
        ex to_polynomial(exmap & repl) const override;
        numeric integer_content() const override;
index 1f1f1b06aeb618ed3c396defa34a16b93b2dfdd0..9341d277c3e7c8957b162b49f9c8798054a680c3 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's overloaded operators. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index fc5aa3046a6879e594f39bef8b5df4df03844f63..45062aedb6d6130da8c2533d757df42d1219fa92 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's overloaded operators. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index a74005f454f54dcf51016a49b2bed7c8d2295d42..ca5a63a63c1024d97c1bc0250dee41d0b6378af9 100644 (file)
@@ -3,7 +3,7 @@
  *  Debugging facilities for parser. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 62c0a506298a048dbca484c6d23683f02e519f0c..defcc87af59ecb02dc26ce1fb27ea222a2de5a2c 100644 (file)
@@ -4,7 +4,7 @@
  **/
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -69,32 +69,20 @@ private:
        registered_functions_hack& operator=(const registered_functions_hack&);
 };
 
-// Encode an integer into a pointer to a function. Since functions
-// are aligned (the minimal alignment depends on CPU architecture)
-// we can distinguish between pointers and integers.
-static reader_func encode_serial_as_reader_func(unsigned serial)
-{
-       uintptr_t u = (uintptr_t)serial;
-       u = (u << 1) | (uintptr_t)1;
-       reader_func ptr = (reader_func)((void *)u);
-       return ptr;
-}
-
 const prototype_table& get_default_reader()
 {
-       using std::make_pair;
        static bool initialized = false;
        static prototype_table reader;
        if (!initialized) {
-               
-               reader[make_pair("sqrt", 1)] = sqrt_reader;
-               reader[make_pair("pow", 2)] = pow_reader;
-               reader[make_pair("power", 2)] = power_reader;
-               reader[make_pair("lst", 0)] = lst_reader;
+
+               reader.insert({{"sqrt", 1}, reader_func(sqrt_reader)});
+               reader.insert({{"pow", 2}, reader_func(pow_reader)});
+               reader.insert({{"power", 2}, reader_func(power_reader)});
+               reader.insert({{"lst", 0}, reader_func(lst_reader)});
                unsigned serial = 0;
                for (auto & it : registered_functions_hack::get_registered_functions()) {
-                       prototype proto = make_pair(it.get_name(), it.get_nparams());
-                       reader[proto] = encode_serial_as_reader_func(serial);
+                       reader.insert({{it.get_name(), it.get_nparams()},
+                                      reader_func(serial)});
                        ++serial;
                }
                initialized = true;
@@ -104,15 +92,14 @@ const prototype_table& get_default_reader()
 
 const prototype_table& get_builtin_reader()
 {
-       using std::make_pair;
        static bool initialized = false;
        static prototype_table reader;
        if (!initialized) {
-               
-               reader[make_pair("sqrt", 1)] = sqrt_reader;
-               reader[make_pair("pow", 2)] = pow_reader;
-               reader[make_pair("power", 2)] = power_reader;
-               reader[make_pair("lst", 0)] = lst_reader;
+
+               reader.insert({{"sqrt", 1}, reader_func(sqrt_reader)});
+               reader.insert({{"pow", 2}, reader_func(pow_reader)});
+               reader.insert({{"power", 2}, reader_func(power_reader)});
+               reader.insert({{"lst", 0}, reader_func(lst_reader)});
                enum {
                        log,
                        exp,
@@ -146,8 +133,8 @@ const prototype_table& get_builtin_reader()
                auto it = registered_functions_hack::get_registered_functions().begin();
                unsigned serial = 0;
                for ( ; serial<NFUNCTIONS; ++it, ++serial ) {
-                       prototype proto = make_pair(it->get_name(), it->get_nparams());
-                       reader[proto] = encode_serial_as_reader_func(serial);
+                       reader.insert({{it->get_name(), it->get_nparams()},
+                                      reader_func(serial)});
                }
                initialized = true;
        }
index b5d59ba6f7eedb332c6dd95a1ae89815591fd4cb..18576aff631c6bbf5004f42b6a46234bf9219a04 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's lexer. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index b6429bf459e2f0706508a5503c583ce36d04fa04..436fe843f531c2a101df1e0493984e2f8fe721d4 100644 (file)
@@ -3,7 +3,7 @@
  *  The lexer. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 00e7ffd0919b32f5227a5b24cd19faffa315dc95..7459bdfdfe87d3e79191af0d34cfc379d8981b29 100644 (file)
@@ -3,7 +3,7 @@
  *  Code to deal with binary operators. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -114,6 +114,18 @@ ex parser::parse_binop_rhs(int expr_prec, ex& lhs)
        }
 }
 
+/// unary_expr: [+-] expression
+ex parser::parse_unary_expr()
+{
+       // Parse a binary expression with the priority of exponentiation
+       // or higher. Ignore the overall sign, because parse_primary()
+       // handles it for us.
+       get_next_tok(); // Skip [+-]
+       ex lhs = parse_primary();
+       ex e = parse_binop_rhs(get_tok_prec('^'), lhs);
+       return e;
+}
+
 extern const numeric* _num_1_p;
 
 static ex make_minus_expr(const exvector& args)
@@ -137,6 +149,16 @@ static ex make_divide_expr(const exvector& args)
        return dynallocate<mul>(args[0], rest);
 }
 
+static ex make_power_expr(const exvector& args)
+{
+       size_t n = args.size();
+       ex p = pow(args[n - 2], args[n - 1]);
+       for (size_t i = n - 2; i > 0; i--) {
+               p = pow(args[i - 1], p);
+       }
+       return p;
+}
+
 static ex make_binop_expr(const int binop, const exvector& args)
 {
        switch (binop) {
@@ -149,11 +171,7 @@ static ex make_binop_expr(const int binop, const exvector& args)
                case '/':
                        return make_divide_expr(args);
                case '^':
-                       if (args.size() != 2)
-                               throw std::invalid_argument(
-                                               std::string(__func__) 
-                                               + ": power should have exactly 2 operands");
-                       return pow(args[0], args[1]);
+                       return make_power_expr(args);
                default:
                        throw std::invalid_argument(
                                        std::string(__func__) 
index a8cdf021e8b1be75f491074eccc5bbd6233edb17..8d0298162021a0f6ec6c37d11dbd19b214917fff 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of the parser context. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 3cb033333c70a3b78c280b3e6ca262ddfd09dcff..015ca13517dbce52410fa67a8317030e5a3ce30f 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to parser context. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -63,7 +63,21 @@ typedef std::pair<std::string, std::size_t> prototype;
  * The parser uses (an associative array of) such functions to construct
  * (GiNaC) classes and functions from a sequence of characters.
  */
-typedef ex (*reader_func)(const exvector& args);
+class reader_func {
+       enum { FUNCTION_PTR, GINAC_FUNCTION };
+public:
+       reader_func(ex (*func_)(const exvector& args))
+               : type(FUNCTION_PTR), serial(0), func(func_) {}
+       reader_func(unsigned serial_)
+               : type(GINAC_FUNCTION), serial(serial_), func(nullptr) {}
+       ex operator()(const exvector& args) const;
+private:
+       unsigned type;
+       unsigned serial;
+       ex (*func)(const exvector& args);
+};
+
+
 
 /**
  * Prototype table.
index b0a743316e22b473dc5c3ce5646ff66a812eb0b1..a7288c32a6b3e614c6b06adc910a5fff2fcb9e99 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's parser. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
 #include "mul.h"
 #include "constant.h"
 #include "function.h"
+#include "operators.h"
 
 #include <cstdint> // for uintptr_t
 #include <sstream>
 
 namespace GiNaC {
 
-// <KLUDGE>
-// Find out if ptr is a pointer to a function or a specially crafted integer.
-// It's possible to distinguish between these because functions are aligned.
-// Returns true if ptr is a pointer and false otherwise.
-static bool decode_serial(unsigned& serial, const reader_func ptr)
+ex reader_func::operator()(const exvector& args) const
 {
-       uintptr_t u = (uintptr_t)(void *)ptr;
-       if (u & 1) {
-               u >>= 1;
-               serial = (unsigned)u;
-               return false;
-       }
-       return true;
-}
-
-// Figures out if ptr is a pointer to function or a serial of GiNaC function.
-// In the former case calls that function, in the latter case constructs
-// GiNaC function with corresponding serial and arguments.
-static ex dispatch_reader_fcn(const reader_func ptr, const exvector& args)
-{
-       unsigned serial = 0; // dear gcc, could you please shut up?
-       bool is_ptr = decode_serial(serial, ptr);
-       if (is_ptr)
-               return ptr(args);
-       else
+       switch (type) {
+       case FUNCTION_PTR:
+               return func(args);
+       case GINAC_FUNCTION:
                return function(serial, args);
+       default:
+               abort();
+       }
 }
-// </KLUDGE>
-
 
 /// identifier_expr:  identifier |  identifier '(' expression* ')'
 ex parser::parse_identifier_expr()
@@ -92,16 +75,14 @@ ex parser::parse_identifier_expr()
        }
        // Eat the ')'.
        get_next_tok();
-       prototype the_prototype = make_pair(name, args.size());
-       auto reader = funcs.find(the_prototype);
+       auto reader = funcs.find({name, args.size()});
        if (reader == funcs.end()) {
                Parse_error_("no function \"" << name << "\" with " <<
                             args.size() << " arguments");
        }
        // reader->second might be a pointer to a C++ function or a specially
        // crafted serial of a GiNaC::function.
-       ex ret = dispatch_reader_fcn(reader->second, args);
-       return ret;
+       return reader->second(args);
 }
 
 /// paren_expr:  '(' expression ')'
@@ -144,27 +125,6 @@ ex parser::parse_lst_expr()
        return list;
 }
 
-extern const ex _ex0;
-
-/// unary_expr: [+-] expression
-ex parser::parse_unary_expr()
-{
-       // Unlike most other parse_* method this one does NOT consume
-       // current token so parse_binop_rhs() knows what kind of operator
-       // is being parsed.
-       
-       // There are different kinds of expressions which need to be handled:
-       // -a+b 
-       // -(a) 
-       // +a
-       // +(a)
-       // Delegate the work to parse_binop_rhs(), otherwise we end up
-       // duplicating it here. 
-       ex lhs = _ex0; // silly trick
-       ex e = parse_binop_rhs(0, lhs);
-       return e;
-}
-
 /// primary: identifier_expr | number_expr | paren_expr | unary_expr 
 ex parser::parse_primary() 
 {
@@ -178,6 +138,7 @@ ex parser::parse_primary()
                case '{': 
                         return parse_lst_expr();
                case '-':
+                        return -parse_unary_expr();
                case '+':
                         return parse_unary_expr();
                case lexer::token_type::literal:
@@ -225,7 +186,7 @@ ex parser::operator()(std::istream& input)
        get_next_tok();
        ex ret = parse_expression();
        // parse_expression() stops if it encounters an unknown token.
-       // This is not a bug: since the parser is recursive checking
+       // This is not a bug: since the parser is recursive, checking
        // whether the next token is valid is responsibility of the caller.
        // Hence make sure nothing is left in the stream:
        if (token != lexer::token_type::eof)
index 607d7f77166ccd438b6927187c10f01a1f0ef96b..08fc6c17a5b1cb06c499a764bf136fba56029e5e 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to the parser. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 1395eb0f1422d0c6936543b53c4784f64396b5a5..030a301fa4424dc1d750a5cc029bd61c70306992 100644 (file)
@@ -3,7 +3,7 @@
  * Parser interface compatible with the old (bison/flex based) parser. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 75a7e39fce5100e6efa99c4703f8ff7fd35b768e..ad79785c372f869673a038fd53832e241a0c8982 100644 (file)
@@ -3,7 +3,7 @@
  *  Chinese remainder algorithm. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 5945640b6e0c39380d44fe4bfee90ad75b96ed6b..460b05635cbc290408c38f5e2dd0845399b2f57a 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GCD functions using Chinese remainder algorithm. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 6beda76fc574a0c8f375dce15efc1bb620f80940..1200563722fd89c4db64ae95609ac9885c31cf32 100644 (file)
@@ -3,7 +3,7 @@
  *  Utility functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index c18cc45d23b4e6ffaf6ea20935e59100c13796f9..82293a13fc61be0dec3b1922c804eaafcac1f104 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to utility functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 845b5aa18d20d9da02a725d794912dd3d45efadb..b01e71759a8c7c926230318d71f3739c5612ed95 100644 (file)
@@ -3,7 +3,7 @@
  *  Garner's algorithm. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 9bdcd2ffdaebc6f42f56e9dd30f21808385347ab..3b3672825022a80ca9027d5006de4fd16e4390ee 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to Garner's algorithm. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 5f191165cfaa3e1ce70dec0a4886b18bcceec44f..5f0eecd6876374ba9e7c0a356d8549ef7360ef82 100644 (file)
@@ -3,7 +3,7 @@
  *  Utility macros and functions for debugging. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 7534c53ef46c30c25eb518d4e29ce314f54bda25..5d9d4acb4c522d192de9749ea72b7ddcad2ed35e 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of polynomial division in Z/Zp. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 4c7337889dea82b69bf585167565a43960cc446a..49c2401c4815df2997687cf48582eaf056d5ad3a 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to polynomial division in Z/Zp. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index ac6c4526084837fec8376a4fddb7ec152375924e..412e987cbef9fa434a3016ab5e3c77edfbb3aca3 100644 (file)
@@ -3,7 +3,7 @@
  *  Euclidean GCD and supporting functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index d071942d0f0e8d415128f6d99c6573e082390b52..c5c383fb85407c84882d39faf822370c8457e35d 100644 (file)
@@ -3,7 +3,7 @@
  *  Functions for finding an evaluation point. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 6e629b0e2835d6745223916a9e93cc1fd1ab5196..1a3c127e3b0f03aed8e0a09030c7c04cf54b6c6d 100644 (file)
@@ -3,7 +3,7 @@
  *  Numerical evaluation of univariate polynomials. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 237c2658ad66f1d7f7c7242e71195389e19bec50..8d00b65c47eb5f534245be165f41f9d754366d0e 100644 (file)
@@ -3,7 +3,7 @@
  *  GCD using Euclidean algorithm. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index fdc3bdf4fb8bd423ef9a70f9ebde798e0fdbe9d5..2fa6f12a86df7c600ecb66c1a1740a899c5ea23e 100644 (file)
@@ -3,7 +3,7 @@
  *  Several GCD algorithms. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 4023adb5d247a5c93584c73c8181c86967a1325b..f00dbe90eb9486c2ea207510b4e64cd9b4951ebf 100644 (file)
@@ -3,7 +3,7 @@
  *  Heuristic GCD code. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index c67f98479685a4f0269f8021140be0bcbf46ae30..ba4aa2a33e6779440ebb384d458f8d315ea005d3 100644 (file)
@@ -3,7 +3,7 @@
  *  Utility function for interpolation. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index a0d3e35fe9d77624fe95483e5b0c73a00b1ec566..de007df3c56a9f660377d247574e50f736df001e 100644 (file)
@@ -3,7 +3,7 @@
  *  Chinese remainder algorithm. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 8084bb993af6e6870f94296b9964472ca1512b06..abfbe151efb903bb0118bc3d7535a36c6ab07ef0 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of modular GCD. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index afdee10614dfc823b53bed41b51f3c198f219e22..df17893998c5185d385495faaf9c68e328400278 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to modular GCD. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index dd00aba4e60d643f36670e95d2a2fd90b2a3b3f7..32a083d758f2092a4f92b8e6334921534a975aeb 100644 (file)
@@ -3,7 +3,7 @@
  *  Functions for Newton interpolation. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 7df3c536a930b11f05190c6cbba1721b220e0781..c7b54d389bdd8fc450ac4c4393b439c145733af9 100644 (file)
@@ -3,7 +3,7 @@
  *  Functions to normalize polynomials in a field. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index f0f6fa046394d79e4d8455078960cd53d1edeae3..9186ebddfb0a174a7607a0d9a9449f7875188be4 100644 (file)
@@ -3,7 +3,7 @@
  *  Functions to normalize polynomials in a field. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index d218e31b0efb1db60ca8fe3b7b9e64d8cccf339b..dc506bf3ad21387bfa2a455a2f51ad2d1c7123bc 100644 (file)
@@ -3,7 +3,7 @@
  *  Functions to optimize the choice of variable for multivariate GCD. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index a620cbfd8cbfb1420efe14bf8c0f2d0780db9b83..5a7877b8f4813e200009fcb9dfa206d4ab02ce62 100644 (file)
@@ -4,7 +4,7 @@
  *  computations. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e8b7357f563905fbc1e5087ae86d4ebdb91698ab..a0ba6f8848cdd85508c05dc082992e00ff507a02 100644 (file)
@@ -3,7 +3,7 @@
  *  GCD for polynomials in prime field. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index e46500cde160fa729a4d049d0ecf18ad24acd2a2..c8363ac7a5e5499c0af68edfbdbf27074fb8534f 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GCD functions for polynomials over prime fields. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 7f81a672ce6d61bcaa72e91a3a3bebe652af9417..f080ab8154155270bac8a43a35984785dd0e2a74 100644 (file)
@@ -3,7 +3,7 @@
  *  Chinese remainder algorithm. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 754b09ea3e3d7ed96f373654d1286d1e2dd2c316..f301c111674d21ef69978293b76be1394576520d 100644 (file)
@@ -3,7 +3,7 @@
  *  Function to calculate the pseudo-remainder. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 803c56730f7c63d55111c8670d8226f674adf04c..c9997e7e754e2c2c497848df80dc51d3ddc5e915 100644 (file)
@@ -3,7 +3,7 @@
  *  Factory for prime numbers. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 2db82588f3a744315a6393f3428cb7ccfbb27678..315daa8ea45945c181c3a6083e4b7210512e785f 100644 (file)
@@ -3,7 +3,7 @@
  *  Function to find primitive part of a multivariate polynomial. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 027082f64e61368e1d03a710811b7f47f33e6234..41d5483ad45465eecd8e5c90b340eeadf1b1cee4 100644 (file)
@@ -3,7 +3,7 @@
  *  Functions calculating remainders. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 5e82149825a027bf6f3ea185e9ce51be11deb5e5..e4123230b0c9decd8688107f4c78f7e018f0c566 100644 (file)
@@ -3,7 +3,7 @@
  *  Functions calculating remainders. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index a8dd56c16d02da38d002ac8b5cf6e45d4e4c922c..1a5b7a5df6897d2fc4dd56d887e9c0486a42d762 100644 (file)
@@ -3,7 +3,7 @@
  *  Functions for polynomial ring arithmetic. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index d3d531b78f80726c9699f4c5f9efe5d7fb6551ce..f542a8d95c51ec95b50bc878e1ba0039271d70f0 100644 (file)
@@ -3,7 +3,7 @@
  *  Utility functions for modular arithmetic. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 0c9d2da104103e4e70440b7e1594cecfe55bcf15..725a7ecb772a3bd2d76d6e6572691a27c24e7338 100644 (file)
@@ -3,7 +3,7 @@
  *  GCD function for univariate polynomials using PRS method. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 2c59a0038db5b1d2aa4d5c613effe604945e05a9..71bb671f01216daaeb90cbb452fcac178f73d7e8 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to polynomials with integer and modular coefficients. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index a49e5bd231a126f7b5a30967f8a1c438d2c115b1..d60bc963010c4dc793e2e6ac721f48678b30c484 100644 (file)
@@ -3,7 +3,7 @@
  *  Input/Output function for univariate polynomials. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 9171371bbdf1f54924cab88d02d4c8f41ebdc8ab..66d02fe57bc073fdaff0da3f9106562502317f36 100644 (file)
@@ -3,7 +3,7 @@
  *  Output operators for polynomials. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index c4ea9db19649b4008936ea86be3904ba8d2b0719..c30c9547975139713fceb0aa4db1cf15f840859d 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's symbolic exponentiation (basis^exponent). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -140,7 +140,7 @@ void power::do_print_latex(const print_latex & c, unsigned level) const
 static void print_sym_pow(const print_context & c, const symbol &x, int exp)
 {
        // Optimal output of integer powers of symbols to aid compiler CSE.
-       // C.f. ISO/IEC 14882:2011, section 1.9 [intro execution], paragraph 15
+       // C.f. ISO/IEC 14882:2011, section 1.9 [intro.execution], paragraph 15
        // to learn why such a parenthesation is really necessary.
        if (exp == 1) {
                x.print(c);
@@ -619,7 +619,7 @@ ex power::subs(const exmap & m, unsigned options) const
 
        if (!are_ex_trivially_equal(basis, subsed_basis)
         || !are_ex_trivially_equal(exponent, subsed_exponent)) 
-               return power(subsed_basis, subsed_exponent).subs_one_level(m, options);
+               return dynallocate<power>(subsed_basis, subsed_exponent);
 
        if (!(options & subs_options::algebraic))
                return subs_one_level(m, options);
@@ -809,9 +809,10 @@ ex power::expand(unsigned options) const
                ex coeff=(possign? _ex1 : _ex_1);
                if (m.overall_coeff.info(info_flags::positive) && m.overall_coeff != _ex1)
                        prodseq.push_back(pow(m.overall_coeff, exponent));
-               else if (m.overall_coeff.info(info_flags::negative) && m.overall_coeff != _ex_1)
+               else if (m.overall_coeff.info(info_flags::negative) && m.overall_coeff != _ex_1) {
                        prodseq.push_back(pow(-m.overall_coeff, exponent));
-               else
+                       coeff = -coeff;
+               } else
                        coeff *= m.overall_coeff;
 
                // If positive/negative factors are found, then extract them.
@@ -1010,16 +1011,16 @@ ex power::expand_add(const add & a, long n, unsigned options)
                                                // optimize away
                                        } else if (exponent[i] == 1) {
                                                // optimized
-                                               monomial.push_back(expair(r, _ex1));
+                                               monomial.emplace_back(expair(r, _ex1));
                                                if (c != *_num1_p)
                                                        factor = factor.mul(c);
                                        } else { // general case exponent[i] > 1
-                                               monomial.push_back(expair(r, exponent[i]));
+                                               monomial.emplace_back(expair(r, exponent[i]));
                                                if (c != *_num1_p)
                                                        factor = factor.mul(c.power(exponent[i]));
                                        }
                                }
-                               result.push_back(expair(mul(std::move(monomial)).expand(options), factor));
+                               result.emplace_back(expair(mul(std::move(monomial)).expand(options), factor));
                        } while (compositions.next());
                } while (partitions.next());
        }
@@ -1063,27 +1064,27 @@ ex power::expand_add_2(const add & a, unsigned options)
                
                if (c.is_equal(_ex1)) {
                        if (is_exactly_a<mul>(r)) {
-                               result.push_back(expair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
-                                                       _ex1));
+                               result.emplace_back(expair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
+                                                          _ex1));
                        } else {
-                               result.push_back(expair(dynallocate<power>(r, _ex2),
-                                                       _ex1));
+                               result.emplace_back(expair(dynallocate<power>(r, _ex2),
+                                                          _ex1));
                        }
                } else {
                        if (is_exactly_a<mul>(r)) {
-                               result.push_back(expair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
-                                                       ex_to<numeric>(c).power_dyn(*_num2_p)));
+                               result.emplace_back(expair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
+                                                          ex_to<numeric>(c).power_dyn(*_num2_p)));
                        } else {
-                               result.push_back(expair(dynallocate<power>(r, _ex2),
-                                                       ex_to<numeric>(c).power_dyn(*_num2_p)));
+                               result.emplace_back(expair(dynallocate<power>(r, _ex2),
+                                                          ex_to<numeric>(c).power_dyn(*_num2_p)));
                        }
                }
 
                for (auto cit1=cit0+1; cit1!=last; ++cit1) {
                        const ex & r1 = cit1->rest;
                        const ex & c1 = cit1->coeff;
-                       result.push_back(expair(mul(r,r1).expand(options),
-                                               _num2_p->mul(ex_to<numeric>(c)).mul_dyn(ex_to<numeric>(c1))));
+                       result.emplace_back(expair(mul(r,r1).expand(options),
+                                                  _num2_p->mul(ex_to<numeric>(c)).mul_dyn(ex_to<numeric>(c1))));
                }
        }
        
index 109d07f2464c4057575f99425d882760fe535ef0..b893870f496a0a7e96ab1e139c8f32fa7b71afd4 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's symbolic exponentiation (basis^exponent). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@ public:
        ex series(const relational & s, int order, unsigned options = 0) const override;
        ex subs(const exmap & m, unsigned options = 0) const override;
        bool has(const ex & other, unsigned options = 0) const override;
-       ex normal(exmap & repl, exmap & rev_lookup) const override;
+       ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
        ex to_rational(exmap & repl) const override;
        ex to_polynomial(exmap & repl) const override;
        ex conjugate() const override;
index 6b18cc6585546b400ef47e0723ec8f645817db78..8f50db7060b07a881a2a29548f11666466bc63a5 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of helper classes for expression output. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 27f69afa934074720e7e05c141b788e79b39abb5..0ded6227bf905a63264fbd5d1135dbe9487e8bf9 100644 (file)
@@ -3,7 +3,7 @@
  *  Definition of helper classes for expression output. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 4dba512951ca60c36c66a51e78e98e2bd311d256..b3ec633ec752cc0aaa1097a70d9e03fbb88fd67f 100644 (file)
@@ -4,7 +4,7 @@
  *  methods for series expansion. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -66,8 +66,7 @@ pseries::pseries() { }
  *  non-terminating series.
  *
  *  @param rel_  expansion variable and point (must hold a relational)
- *  @param ops_  vector of {coefficient, power} pairs (coefficient must not be zero)
- *  @return newly constructed pseries */
+ *  @param ops_  vector of {coefficient, power} pairs (coefficient must not be zero) */
 pseries::pseries(const ex &rel_, const epvector &ops_)
   : seq(ops_)
 {
@@ -119,17 +118,15 @@ pseries::pseries(const ex &rel_, epvector &&ops_)
 void pseries::read_archive(const archive_node &n, lst &sym_lst) 
 {
        inherited::read_archive(n, sym_lst);
-       auto first = n.find_first("coeff");
-       auto last = n.find_last("power");
-       ++last;
-       seq.reserve((last-first)/2);
+       auto range = n.find_property_range("coeff", "power");
+       seq.reserve((range.end-range.begin)/2);
 
-       for (auto loc = first; loc < last;) {
+       for (auto loc = range.begin; loc < range.end;) {
                ex rest;
                ex coeff;
                n.find_ex_by_loc(loc++, rest, sym_lst);
                n.find_ex_by_loc(loc++, coeff, sym_lst);
-               seq.push_back(expair(rest, coeff));
+               seq.emplace_back(expair(rest, coeff));
        }
 
        n.find_ex("var", var, sym_lst);
@@ -396,17 +393,7 @@ ex pseries::collect(const ex &s, bool distributed) const
 /** Perform coefficient-wise automatic term rewriting rules in this class. */
 ex pseries::eval() const
 {
-       if (flags & status_flags::evaluated) {
-               return *this;
-       }
-
-       // Construct a new series with evaluated coefficients
-       epvector new_seq;
-       new_seq.reserve(seq.size());
-       for (auto & it : seq)
-               new_seq.push_back(expair(it.rest, it.coeff));
-
-       return dynallocate<pseries>(relational(var,point), std::move(new_seq)).setflag(status_flags::evaluated);
+       return hold();
 }
 
 /** Evaluate coefficients numerically. */
@@ -416,7 +403,7 @@ ex pseries::evalf() const
        epvector new_seq;
        new_seq.reserve(seq.size());
        for (auto & it : seq)
-               new_seq.push_back(expair(it.rest, it.coeff));
+               new_seq.emplace_back(expair(it.rest.evalf(), it.coeff));
 
        return dynallocate<pseries>(relational(var,point), std::move(new_seq)).setflag(status_flags::evaluated);
 }
@@ -447,7 +434,7 @@ ex pseries::real_part() const
        epvector v;
        v.reserve(seq.size());
        for (auto & it : seq)
-               v.push_back(expair((it.rest).real_part(), it.coeff));
+               v.emplace_back(expair(it.rest.real_part(), it.coeff));
        return dynallocate<pseries>(var==point, std::move(v));
 }
 
@@ -462,7 +449,7 @@ ex pseries::imag_part() const
        epvector v;
        v.reserve(seq.size());
        for (auto & it : seq)
-               v.push_back(expair((it.rest).imag_part(), it.coeff));
+               v.emplace_back(expair(it.rest.imag_part(), it.coeff));
        return dynallocate<pseries>(var==point, std::move(v));
 }
 
@@ -471,7 +458,7 @@ ex pseries::eval_integ() const
        std::unique_ptr<epvector> newseq(nullptr);
        for (auto i=seq.begin(); i!=seq.end(); ++i) {
                if (newseq) {
-                       newseq->push_back(expair(i->rest.eval_integ(), i->coeff));
+                       newseq->emplace_back(expair(i->rest.eval_integ(), i->coeff));
                        continue;
                }
                ex newterm = i->rest.eval_integ();
@@ -480,7 +467,7 @@ ex pseries::eval_integ() const
                        newseq->reserve(seq.size());
                        for (auto j=seq.begin(); j!=i; ++j)
                                newseq->push_back(*j);
-                       newseq->push_back(expair(newterm, i->coeff));
+                       newseq->emplace_back(expair(newterm, i->coeff));
                }
        }
 
@@ -499,7 +486,7 @@ ex pseries::evalm() const
                if (something_changed) {
                        ex newcoeff = i->rest.evalm();
                        if (!newcoeff.is_zero())
-                               newseq.push_back(expair(newcoeff, i->coeff));
+                               newseq.emplace_back(expair(newcoeff, i->coeff));
                } else {
                        ex newcoeff = i->rest.evalm();
                        if (!are_ex_trivially_equal(newcoeff, i->rest)) {
@@ -507,7 +494,7 @@ ex pseries::evalm() const
                                newseq.reserve(seq.size());
                                std::copy(seq.begin(), i, std::back_inserter<epvector>(newseq));
                                if (!newcoeff.is_zero())
-                                       newseq.push_back(expair(newcoeff, i->coeff));
+                                       newseq.emplace_back(expair(newcoeff, i->coeff));
                        }
                }
        }
@@ -530,7 +517,7 @@ ex pseries::subs(const exmap & m, unsigned options) const
        epvector newseq;
        newseq.reserve(seq.size());
        for (auto & it : seq)
-               newseq.push_back(expair(it.rest.subs(m, options), it.coeff));
+               newseq.emplace_back(expair(it.rest.subs(m, options), it.coeff));
        return dynallocate<pseries>(relational(var,point.subs(m, options)), std::move(newseq));
 }
 
@@ -542,7 +529,7 @@ ex pseries::expand(unsigned options) const
        for (auto & it : seq) {
                ex restexp = it.rest.expand();
                if (!restexp.is_zero())
-                       newseq.push_back(expair(restexp, it.coeff));
+                       newseq.emplace_back(expair(restexp, it.coeff));
        }
        return dynallocate<pseries>(relational(var,point), std::move(newseq)).setflag(options == 0 ? status_flags::expanded : 0);
 }
@@ -558,11 +545,11 @@ ex pseries::derivative(const symbol & s) const
                // FIXME: coeff might depend on var
                for (auto & it : seq) {
                        if (is_order_function(it.rest)) {
-                               new_seq.push_back(expair(it.rest, it.coeff - 1));
+                               new_seq.emplace_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));
+                                       new_seq.emplace_back(expair(c, it.coeff - 1));
                        }
                }
 
@@ -574,7 +561,7 @@ ex pseries::derivative(const symbol & s) const
                        } else {
                                ex c = it.rest.diff(s);
                                if (!c.is_zero())
-                                       new_seq.push_back(expair(c, it.coeff));
+                                       new_seq.emplace_back(expair(c, it.coeff));
                        }
                }
        }
@@ -628,7 +615,7 @@ ex basic::series(const relational & r, int order, unsigned options) const
 
        // default for order-values that make no sense for Taylor expansion
        if ((order <= 0) && this->has(s)) {
-               seq.push_back(expair(Order(_ex1), order));
+               seq.emplace_back(expair(Order(_ex1), order));
                return pseries(r, std::move(seq));
        }
 
@@ -638,7 +625,7 @@ ex basic::series(const relational & r, int order, unsigned options) const
        ex coeff = deriv.subs(r, subs_options::no_pattern);
 
        if (!coeff.is_zero()) {
-               seq.push_back(expair(coeff, _ex0));
+               seq.emplace_back(expair(coeff, _ex0));
        }
 
        int n;
@@ -653,13 +640,13 @@ ex basic::series(const relational & r, int order, unsigned options) const
 
                coeff = deriv.subs(r, subs_options::no_pattern);
                if (!coeff.is_zero())
-                       seq.push_back(expair(fac * coeff, n));
+                       seq.emplace_back(expair(fac * coeff, n));
        }
        
        // Higher-order terms, if present
        deriv = deriv.diff(s);
        if (!deriv.expand().is_zero())
-               seq.push_back(expair(Order(_ex1), n));
+               seq.emplace_back(expair(Order(_ex1), n));
        return pseries(r, std::move(seq));
 }
 
@@ -674,13 +661,13 @@ ex symbol::series(const relational & r, int order, unsigned options) const
 
        if (this->is_equal_same_type(ex_to<symbol>(r.lhs()))) {
                if (order > 0 && !point.is_zero())
-                       seq.push_back(expair(point, _ex0));
+                       seq.emplace_back(expair(point, _ex0));
                if (order > 1)
-                       seq.push_back(expair(_ex1, _ex1));
+                       seq.emplace_back(expair(_ex1, _ex1));
                else
-                       seq.push_back(expair(Order(_ex1), numeric(order)));
+                       seq.emplace_back(expair(Order(_ex1), numeric(order)));
        } else
-               seq.push_back(expair(*this, _ex0));
+               seq.emplace_back(expair(*this, _ex0));
        return pseries(r, std::move(seq));
 }
 
@@ -741,12 +728,12 @@ ex pseries::add_series(const pseries &other) const
                } else {
                        // Add coefficient of a and b
                        if (is_order_function((*a).rest) || is_order_function((*b).rest)) {
-                               new_seq.push_back(expair(Order(_ex1), (*a).coeff));
+                               new_seq.emplace_back(expair(Order(_ex1), (*a).coeff));
                                break;  // Order term ends the sequence
                        } else {
                                ex sum = (*a).rest + (*b).rest;
                                if (!(sum.is_zero()))
-                                       new_seq.push_back(expair(sum, numeric(pow_a)));
+                                       new_seq.emplace_back(expair(sum, numeric(pow_a)));
                                ++a;
                                ++b;
                        }
@@ -795,7 +782,7 @@ ex pseries::mul_const(const numeric &other) const
        
        for (auto & it : seq) {
                if (!is_order_function(it.rest))
-                       new_seq.push_back(expair(it.rest * other, it.coeff));
+                       new_seq.emplace_back(expair(it.rest * other, it.coeff));
                else
                        new_seq.push_back(it);
        }
@@ -862,10 +849,10 @@ ex pseries::mul_series(const pseries &other) const
                                co += ita->second * itb->second;
                }
                if (!co.is_zero())
-                       new_seq.push_back(expair(co, numeric(cdeg)));
+                       new_seq.emplace_back(expair(co, numeric(cdeg)));
        }
        if (higher_order_c < std::numeric_limits<int>::max())
-               new_seq.push_back(expair(Order(_ex1), numeric(higher_order_c)));
+               new_seq.emplace_back(expair(Order(_ex1), numeric(higher_order_c)));
        return pseries(relational(var, point), std::move(new_seq));
 }
 
@@ -903,7 +890,7 @@ ex mul::series(const relational & r, int order, unsigned options) const
                bool flag_redo = false;
                try {
                        real_ldegree = buf.expand().ldegree(sym-r.rhs());
-               } catch (std::runtime_error) {}
+               } catch (std::runtime_error &) {}
 
                if (real_ldegree == 0) {
                        if ( factor < 0 ) {
@@ -1005,8 +992,8 @@ ex pseries::power_const(const numeric &p, int deg) const
        // which can easily be solved given the starting value c_0 = (a_0)^p.
        // For the more general case where the leading coefficient of A(x) is not
        // a constant, just consider A2(x) = A(x)*x^m, with some integer m and
-       // repeat the above derivation.  The leading power of C2(x) = A2(x)^2 is
-       // then of course x^(p*m) but the recurrence formula still holds.
+       // repeat the above derivation.  The leading power of C2(x) = A2(x)^p is
+       // then of course a_0^p*x^(p*m) but the recurrence formula still holds.
        
        if (seq.empty()) {
                // as a special case, handle the empty (zero) series honoring the
@@ -1018,16 +1005,27 @@ ex pseries::power_const(const numeric &p, int deg) const
                else
                        return *this;
        }
-       
-       const int ldeg = ldegree(var);
-       if (!(p*ldeg).is_integer())
+
+       const int base_ldeg = ldegree(var);
+       if (!(p*base_ldeg).is_integer())
                throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series");
+       int new_ldeg = (p*base_ldeg).to_int();
+
+       const int base_deg = degree(var);
+       int new_deg = deg;
+       if (p.is_pos_integer()) {
+               // No need to compute beyond p*base_deg.
+               new_deg = std::min((p*base_deg).to_int(), deg);
+       }
 
        // adjust number of coefficients
-       int numcoeff = deg - (p*ldeg).to_int();
+       int numcoeff = new_deg - new_ldeg;
+       if (new_deg < deg)
+               numcoeff += 1;
+
        if (numcoeff <= 0) {
-               epvector epv { expair(Order(_ex1), deg) };
-               return dynallocate<pseries>(relational(var,point), std::move(epv));
+               return dynallocate<pseries>(relational(var, point),
+                                           epvector{{Order(_ex1), deg}});
        }
        
        // O(x^n)^(-m) is undefined
@@ -1037,33 +1035,35 @@ ex pseries::power_const(const numeric &p, int deg) const
        // Compute coefficients of the powered series
        exvector co;
        co.reserve(numcoeff);
-       co.push_back(pow(coeff(var, ldeg), p));
+       co.push_back(pow(coeff(var, base_ldeg), p));
        for (int i=1; i<numcoeff; ++i) {
                ex sum = _ex0;
                for (int j=1; j<=i; ++j) {
-                       ex c = coeff(var, j + ldeg);
+                       ex c = coeff(var, j + base_ldeg);
                        if (is_order_function(c)) {
                                co.push_back(Order(_ex1));
                                break;
                        } else
                                sum += (p * j - (i - j)) * co[i - j] * c;
                }
-               co.push_back(sum / coeff(var, ldeg) / i);
+               co.push_back(sum / coeff(var, base_ldeg) / i);
        }
        
        // Construct new series (of non-zero coefficients)
        epvector new_seq;
        bool higher_order = false;
        for (int i=0; i<numcoeff; ++i) {
-               if (!co[i].is_zero())
-                       new_seq.push_back(expair(co[i], p * ldeg + i));
+               if (!co[i].is_zero()) {
+                       new_seq.emplace_back(expair(co[i], new_ldeg + i));
+               }
                if (is_order_function(co[i])) {
                        higher_order = true;
                        break;
                }
        }
-       if (!higher_order)
-               new_seq.push_back(expair(Order(_ex1), p * ldeg + numcoeff));
+       if (!higher_order && new_deg == deg) {
+               new_seq.emplace_back(expair{Order(_ex1), new_deg});
+       }
 
        return pseries(relational(var,point), std::move(new_seq));
 }
@@ -1092,14 +1092,14 @@ ex power::series(const relational & r, int order, unsigned options) const
        bool must_expand_basis = false;
        try {
                basis.subs(r, subs_options::no_pattern);
-       } catch (pole_error) {
+       } catch (pole_error &) {
                must_expand_basis = true;
        }
 
        bool exponent_is_regular = true;
        try {
                exponent.subs(r, subs_options::no_pattern);
-       } catch (pole_error) {
+       } catch (pole_error &) {
                exponent_is_regular = false;
        }
 
@@ -1133,9 +1133,9 @@ ex power::series(const relational & r, int order, unsigned options) const
        if (basis.is_equal(r.lhs() - r.rhs())) {
                epvector new_seq;
                if (ex_to<numeric>(exponent).to_int() < order)
-                       new_seq.push_back(expair(_ex1, exponent));
+                       new_seq.emplace_back(expair(_ex1, exponent));
                else
-                       new_seq.push_back(expair(Order(_ex1), exponent));
+                       new_seq.emplace_back(expair(Order(_ex1), exponent));
                return pseries(r, std::move(new_seq));
        }
 
@@ -1163,12 +1163,13 @@ ex power::series(const relational & r, int order, unsigned options) const
 
        if (!(real_ldegree*numexp).is_integer())
                throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series");
-       ex e = basis.series(r, (order + real_ldegree*(1-numexp)).to_int(), options);
+       int extra_terms = (real_ldegree*(1-numexp)).to_int();
+       ex e = basis.series(r, order + std::max(0, extra_terms), options);
        
        ex result;
        try {
                result = ex_to<pseries>(e).power_const(numexp, order);
-       } catch (pole_error) {
+       } catch (pole_error &) {
                epvector ser { expair(Order(_ex1), order) };
                result = pseries(r, std::move(ser));
        }
@@ -1192,7 +1193,7 @@ ex pseries::series(const relational & r, int order, unsigned options) const
                        for (auto & it : seq) {
                                int o = ex_to<numeric>(it.coeff).to_int();
                                if (o >= order) {
-                                       new_seq.push_back(expair(Order(_ex1), o));
+                                       new_seq.emplace_back(expair(Order(_ex1), o));
                                        break;
                                }
                                new_seq.push_back(it);
@@ -1218,7 +1219,7 @@ ex integral::series(const relational & r, int order, unsigned options) const
                        ? currcoeff
                        : integral(x, a.subs(r), b.subs(r), currcoeff);
                if (currcoeff != 0)
-                       fexpansion.push_back(
+                       fexpansion.emplace_back(
                                expair(currcoeff, ex_to<pseries>(fseries).exponop(i)));
        }
 
index 86c369e6fdff361623d7c6db8174367d7761c258..0f60fc669384a032400b4c7348e4248452b6296c 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to class for extended truncated power series. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -54,7 +54,7 @@ public:
        ex evalf() const override;
        ex series(const relational & r, int order, unsigned options = 0) const override;
        ex subs(const exmap & m, unsigned options = 0) const override;
-       ex normal(exmap & repl, exmap & rev_lookup) const override;
+       ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
        ex expand(unsigned options = 0) const override;
        ex conjugate() const override;
        ex real_part() const override;
index baf0f991c15271c25a0d1a4ad5c7d4d5b40d8e6c..4bfda5db516fdc43a538391ff848eca914888f8f 100644 (file)
@@ -3,7 +3,7 @@
  *  Reference-counted pointer template. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index b051ec4f15512c78d2f8f30b46bb1f2fb4191369..cd628a94cb61d0231109909460ffde08e64fa202 100644 (file)
@@ -3,7 +3,7 @@
  *  GiNaC's class registrar (for class basic and all classes derived from it). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index c6cdc412aa55eba4eb22917f61da392ddc1d41aa..be1a5c9a0f5ac6420908808a281eca976bad0b9a 100644 (file)
@@ -3,7 +3,7 @@
  *  GiNaC's class registrar (for class basic and all classes derived from it). */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 92b54318392afd8ea89120522a0345ba6dc2f5b5..8607dca905884246bd70d2e442cb6e0491f4376a 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of relations between expressions */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -223,8 +223,8 @@ int relational::compare_same_type(const basic & other) const
                                return (o < oth.o) ? -1 : 1;
                        break;
        }
-       const int lcmpval = lh.compare(oth.rh);
-       return (lcmpval!=0) ? lcmpval : rh.compare(oth.lh);
+       const int lcmpval = lh.compare(oth.lh);
+       return (lcmpval!=0) ? lcmpval : rh.compare(oth.rh);
 }
 
 bool relational::match_same_type(const basic & other) const
@@ -308,27 +308,51 @@ relational::safe_bool relational::make_safe_bool(bool cond) const
  *  unequal or undecidable). */
 relational::operator relational::safe_bool() const
 {
-       const ex df = lh-rh;
-       if (!is_exactly_a<numeric>(df))
-               // cannot decide on non-numerical results
-               return o==not_equal ? make_safe_bool(true) : make_safe_bool(false);
-
-       switch (o) {
-               case equal:
-                       return make_safe_bool(ex_to<numeric>(df).is_zero());
-               case not_equal:
-                       return make_safe_bool(!ex_to<numeric>(df).is_zero());
-               case less:
-                       return make_safe_bool(ex_to<numeric>(df)<(*_num0_p));
-               case less_or_equal:
-                       return make_safe_bool(ex_to<numeric>(df)<=(*_num0_p));
-               case greater:
-                       return make_safe_bool(ex_to<numeric>(df)>(*_num0_p));
-               case greater_or_equal:
-                       return make_safe_bool(ex_to<numeric>(df)>=(*_num0_p));
-               default:
-                       throw(std::logic_error("invalid relational operator"));
+       const ex df = lh-rh;  // like ::canonical() method
+       // We treat numeric and symbolic expression differently
+       if (is_exactly_a<numeric>(df)) {
+               switch (o) {
+                       case equal:
+                               return make_safe_bool(ex_to<numeric>(df).is_zero());
+                       case not_equal:
+                               return make_safe_bool(!ex_to<numeric>(df).is_zero());
+                       case less:
+                               return make_safe_bool(ex_to<numeric>(df)<(*_num0_p));
+                       case less_or_equal:
+                               return make_safe_bool(ex_to<numeric>(df)<=(*_num0_p));
+                       case greater:
+                               return make_safe_bool(ex_to<numeric>(df)>(*_num0_p));
+                       case greater_or_equal:
+                               return make_safe_bool(ex_to<numeric>(df)>=(*_num0_p));
+                       default:
+                               throw(std::logic_error("invalid relational operator"));
+               }
+       } else {
+               // The conversion for symbolic expressions is based on the info flags
+               switch (o) {
+                       case equal:
+                               return make_safe_bool(df.is_zero());
+                       case not_equal:
+                               return make_safe_bool(! df.is_zero());
+                       case less:
+                               return make_safe_bool(df.info(info_flags::negative));
+                       case less_or_equal:
+                               return make_safe_bool((-df).info(info_flags::nonnegative));
+                       case greater:
+                               return make_safe_bool(df.info(info_flags::positive));
+                       case greater_or_equal:
+                               return make_safe_bool(df.info(info_flags::nonnegative));
+                       default:
+                               throw(std::logic_error("invalid relational operator"));
+               }
        }
 }
 
+/** Returns an equivalent relational with zero right-hand side.
+ */
+ex relational::canonical() const
+{
+       return relational(lh-rh, _ex0, o);
+}
+
 } // namespace GiNaC
index ac6caecfd801425de214b380f8a7df0c8fff2a9c..5fd8b27116fde777eea21d042bff15e1869810db 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to relations between expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -63,6 +63,8 @@ public:
        void archive(archive_node& n) const override;
        /** Read (a.k.a. deserialize) object from archive. */
        void read_archive(const archive_node& n, lst& syms) override;
+       ex canonical() const;
+
 protected:
        ex eval_ncmul(const exvector & v) const override;
        bool match_same_type(const basic & other) const override;
index 28feedc4009dbbb260ad4aae155a43cdfa4623dd..3e0db834065a4430effb8841d765d305858e688d 100644 (file)
@@ -4,7 +4,7 @@
  *  in GiNaC functions */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 2f867d8edd7e0ac906dba2f4ca569e382cbf0b78..4fe1736880743d306b0713fbd62152a6e2b62a97 100644 (file)
@@ -4,7 +4,7 @@
  *  in GiNaC functions */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 3879629aa8043cdb88b53de7c7b3257accb73890..acea1c38169d090f3d0c3305a789da4c67dbc3a9 100644 (file)
@@ -3,7 +3,7 @@
  *  Wrapper template for making GiNaC classes out of C++ structures. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -178,7 +178,7 @@ public:
        ex series(const relational & r, int order, unsigned options = 0) const override { return inherited::series(r, order, options); }
 
        // rational functions
-       ex normal(exmap & repl, exmap & rev_lookup) const override { return inherited::normal(repl, rev_lookup); }
+       ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override { return inherited::normal(repl, rev_lookup, modifier); }
        ex to_rational(exmap & repl) const override { return inherited::to_rational(repl); }
        ex to_polynomial(exmap & repl) const override { return inherited::to_polynomial(repl); }
 
index b7241d52778721e7908eeff350626c00601a382b..1f25f0d67a8e2120da87ed245651a77901623928 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's symbolic objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 131af5f76fd392090c73c43e62c65378d8090acc..ea37a5efc1e773d5dbeecd16ae67fbf2aa7aca3d 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's symbolic objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ public:
        ex evalf() const override { return *this; } // overwrites basic::evalf() for performance reasons
        ex series(const relational & s, int order, unsigned options = 0) const override;
        ex subs(const exmap & m, unsigned options = 0) const override { return subs_one_level(m, options); } // overwrites basic::subs() for performance reasons
-       ex normal(exmap & repl, exmap & rev_lookup) const override;
+       ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
        ex to_rational(exmap & repl) const override;
        ex to_polynomial(exmap & repl) const override;
        ex conjugate() const override;
index 115df0bfe4924505dfc507eadf08754b592afada..159d18f3c61f5159051696f8712ce2debdd12da2 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's symmetry definitions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 4f921fdf8f686955de22409500cce043f99a9094..f46e66d3970c0ebef9b76933a177b7ee263c613a 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's symmetry definitions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 2f12154d7023556911ea176c2478d74d3cab45bf..4ad07dd30fb8a24cfbc65c2403d34da53d1e5a75 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's special tensors. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index a4b14578e8203bada3cb9771b642ea43b805a9e4..b0c86308521cf5b5e9f68e33b956068513855ea6 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's special tensors. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 6935bcd8e1a71fc93b436efc96b4fb8aa09ea2dd..4750a029090be8a87244a8af8a3115feaf8b94f0 100644 (file)
@@ -4,7 +4,7 @@
  *  but not of any interest to the user of the library. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -67,211 +67,11 @@ multinomial_coefficient(const std::vector<unsigned> & p)
        return factorial(n).div(d);
 }
 
-//////////
-// flyweight chest of numbers is initialized here:
-//////////
 
 /** How many static objects were created?  Only the first one must create
  *  the static flyweights on the heap. */
 int library_init::count = 0;
 
-// static numeric -120
-const numeric *_num_120_p;
-const ex _ex_120 = _ex_120;
-
-// static numeric -60
-const numeric *_num_60_p;
-const ex _ex_60 = _ex_60;
-
-// static numeric -48
-const numeric *_num_48_p;
-const ex _ex_48 = _ex_48;
-
-// static numeric -30
-const numeric *_num_30_p;
-const ex _ex_30 = _ex_30;
-
-// static numeric -25
-const numeric *_num_25_p;
-const ex _ex_25 = _ex_25;
-
-// static numeric -24
-const numeric *_num_24_p;
-const ex _ex_24 = _ex_24;
-
-// static numeric -20
-const numeric *_num_20_p;
-const ex _ex_20 = _ex_20;
-
-// static numeric -18
-const numeric *_num_18_p;
-const ex _ex_18 = _ex_18;
-
-// static numeric -15
-const numeric *_num_15_p;
-const ex _ex_15 = _ex_15;
-
-// static numeric -12
-const numeric *_num_12_p;
-const ex _ex_12 = _ex_12;
-
-// static numeric -11
-const numeric *_num_11_p;
-const ex _ex_11 = _ex_11;
-
-// static numeric -10
-const numeric *_num_10_p;
-const ex _ex_10 = _ex_10;
-
-// static numeric -9
-const numeric *_num_9_p;
-const ex _ex_9 = _ex_9;
-
-// static numeric -8
-const numeric *_num_8_p;
-const ex _ex_8 = _ex_8;
-
-// static numeric -7
-const numeric *_num_7_p;
-const ex _ex_7 = _ex_7;
-
-// static numeric -6
-const numeric *_num_6_p;
-const ex _ex_6 = _ex_6;
-
-// static numeric -5
-const numeric *_num_5_p;
-const ex _ex_5 = _ex_5;
-
-// static numeric -4
-const numeric *_num_4_p;
-const ex _ex_4 = _ex_4;
-
-// static numeric -3
-const numeric *_num_3_p;
-const ex _ex_3 = _ex_3;
-
-// static numeric -2
-const numeric *_num_2_p;
-const ex _ex_2 = _ex_2;
-
-// static numeric -1
-const numeric *_num_1_p;
-const ex _ex_1 = _ex_1;
-
-// static numeric -1/2
-const numeric *_num_1_2_p;
-const ex _ex_1_2= _ex_1_2;
-
-// static numeric -1/3
-const numeric *_num_1_3_p;
-const ex _ex_1_3= _ex_1_3;
-
-// static numeric -1/4
-const numeric *_num_1_4_p;
-const ex _ex_1_4= _ex_1_4;
-
-// static numeric 0
-const numeric *_num0_p;
-const basic *_num0_bp;
-const ex _ex0 = _ex0;
-
-// static numeric 1/4
-const numeric *_num1_4_p;
-const ex _ex1_4 = _ex1_4;
-
-// static numeric 1/3
-const numeric *_num1_3_p;
-const ex _ex1_3 = _ex1_3;
-
-// static numeric 1/2
-const numeric *_num1_2_p;
-const ex _ex1_2 = _ex1_2;
-
-// static numeric 1
-const numeric *_num1_p;
-const ex _ex1 = _ex1;
-
-// static numeric 2
-const numeric *_num2_p;
-const ex _ex2 = _ex2;
-
-// static numeric 3
-const numeric *_num3_p;
-const ex _ex3 = _ex3;
-
-// static numeric 4
-const numeric *_num4_p;
-const ex _ex4 = _ex4;
-
-// static numeric 5
-const numeric *_num5_p;
-const ex _ex5 = _ex5;
-
-// static numeric 6
-const numeric *_num6_p;
-const ex _ex6 = _ex6;
-
-// static numeric 7
-const numeric *_num7_p;
-const ex _ex7 = _ex7;
-
-// static numeric 8
-const numeric *_num8_p;
-const ex _ex8 = _ex8;
-
-// static numeric 9
-const numeric *_num9_p;
-const ex _ex9 = _ex9;
-
-// static numeric 10
-const numeric *_num10_p;
-const ex _ex10 = _ex10;
-
-// static numeric 11
-const numeric *_num11_p;
-const ex _ex11 = _ex11;
-
-// static numeric 12
-const numeric *_num12_p;
-const ex _ex12 = _ex12;
-
-// static numeric 15
-const numeric *_num15_p;
-const ex _ex15 = _ex15;
-
-// static numeric 18
-const numeric *_num18_p;
-const ex _ex18 = _ex18;
-
-// static numeric 20
-const numeric *_num20_p;
-const ex _ex20 = _ex20;
-
-// static numeric 24
-const numeric *_num24_p;
-const ex _ex24 = _ex24;
-
-// static numeric 25
-const numeric *_num25_p;
-const ex _ex25 = _ex25;
-
-// static numeric 30
-const numeric *_num30_p;
-const ex _ex30 = _ex30;
-
-// static numeric 48
-const numeric *_num48_p;
-const ex _ex48 = _ex48;
-
-// static numeric 60
-const numeric *_num60_p;
-const ex _ex60 = _ex60;
-
-// static numeric 120
-const numeric *_num120_p;
-const ex _ex120 = _ex120;
-
 /** Ctor of static initialization helpers.  The fist call to this is going
  *  to initialize the library, the others do nothing. */
 library_init::library_init()
@@ -459,6 +259,211 @@ library_init::~library_init()
 
 void library_init::init_unarchivers() { }
 
+
+//////////
+// Flyweight chest of numbers is re-initialized here. Note that this works
+// because the numeric* have been dynallocated by the library_init ctor before
+// (with the first module that has a static library_init object), so the
+// assignments here only increment their refcounts.
+//////////
+
+// static numeric -120
+const numeric *_num_120_p;
+const ex _ex_120 = ex(*_num_120_p);
+
+// static numeric -60
+const numeric *_num_60_p;
+const ex _ex_60 = ex(*_num_60_p);
+
+// static numeric -48
+const numeric *_num_48_p;
+const ex _ex_48 = ex(*_num_48_p);
+
+// static numeric -30
+const numeric *_num_30_p;
+const ex _ex_30 = ex(*_num_30_p);
+
+// static numeric -25
+const numeric *_num_25_p;
+const ex _ex_25 = ex(*_num_25_p);
+
+// static numeric -24
+const numeric *_num_24_p;
+const ex _ex_24 = ex(*_num_24_p);
+
+// static numeric -20
+const numeric *_num_20_p;
+const ex _ex_20 = ex(*_num_20_p);
+
+// static numeric -18
+const numeric *_num_18_p;
+const ex _ex_18 = ex(*_num_18_p);
+
+// static numeric -15
+const numeric *_num_15_p;
+const ex _ex_15 = ex(*_num_15_p);
+
+// static numeric -12
+const numeric *_num_12_p;
+const ex _ex_12 = ex(*_num_12_p);
+
+// static numeric -11
+const numeric *_num_11_p;
+const ex _ex_11 = ex(*_num_11_p);
+
+// static numeric -10
+const numeric *_num_10_p;
+const ex _ex_10 = ex(*_num_10_p);
+
+// static numeric -9
+const numeric *_num_9_p;
+const ex _ex_9 = ex(*_num_9_p);
+
+// static numeric -8
+const numeric *_num_8_p;
+const ex _ex_8 = ex(*_num_8_p);
+
+// static numeric -7
+const numeric *_num_7_p;
+const ex _ex_7 = ex(*_num_7_p);
+
+// static numeric -6
+const numeric *_num_6_p;
+const ex _ex_6 = ex(*_num_6_p);
+
+// static numeric -5
+const numeric *_num_5_p;
+const ex _ex_5 = ex(*_num_5_p);
+
+// static numeric -4
+const numeric *_num_4_p;
+const ex _ex_4 = ex(*_num_4_p);
+
+// static numeric -3
+const numeric *_num_3_p;
+const ex _ex_3 = ex(*_num_3_p);
+
+// static numeric -2
+const numeric *_num_2_p;
+const ex _ex_2 = ex(*_num_2_p);
+
+// static numeric -1
+const numeric *_num_1_p;
+const ex _ex_1 = ex(*_num_1_p);
+
+// static numeric -1/2
+const numeric *_num_1_2_p;
+const ex _ex_1_2= ex(*_num_1_2_p);
+
+// static numeric -1/3
+const numeric *_num_1_3_p;
+const ex _ex_1_3= ex(*_num_1_3_p);
+
+// static numeric -1/4
+const numeric *_num_1_4_p;
+const ex _ex_1_4= ex(*_num_1_4_p);
+
+// static numeric 0
+const numeric *_num0_p;
+const basic *_num0_bp;
+const ex _ex0 = ex(*_num0_p);
+
+// static numeric 1/4
+const numeric *_num1_4_p;
+const ex _ex1_4 = ex(*_num1_4_p);
+
+// static numeric 1/3
+const numeric *_num1_3_p;
+const ex _ex1_3 = ex(*_num1_3_p);
+
+// static numeric 1/2
+const numeric *_num1_2_p;
+const ex _ex1_2 = ex(*_num1_2_p);
+
+// static numeric 1
+const numeric *_num1_p;
+const ex _ex1 = ex(*_num1_p);
+
+// static numeric 2
+const numeric *_num2_p;
+const ex _ex2 = ex(*_num2_p);
+
+// static numeric 3
+const numeric *_num3_p;
+const ex _ex3 = ex(*_num3_p);
+
+// static numeric 4
+const numeric *_num4_p;
+const ex _ex4 = ex(*_num4_p);
+
+// static numeric 5
+const numeric *_num5_p;
+const ex _ex5 = ex(*_num5_p);
+
+// static numeric 6
+const numeric *_num6_p;
+const ex _ex6 = ex(*_num6_p);
+
+// static numeric 7
+const numeric *_num7_p;
+const ex _ex7 = ex(*_num7_p);
+
+// static numeric 8
+const numeric *_num8_p;
+const ex _ex8 = ex(*_num8_p);
+
+// static numeric 9
+const numeric *_num9_p;
+const ex _ex9 = ex(*_num9_p);
+
+// static numeric 10
+const numeric *_num10_p;
+const ex _ex10 = ex(*_num10_p);
+
+// static numeric 11
+const numeric *_num11_p;
+const ex _ex11 = ex(*_num11_p);
+
+// static numeric 12
+const numeric *_num12_p;
+const ex _ex12 = ex(*_num12_p);
+
+// static numeric 15
+const numeric *_num15_p;
+const ex _ex15 = ex(*_num15_p);
+
+// static numeric 18
+const numeric *_num18_p;
+const ex _ex18 = ex(*_num18_p);
+
+// static numeric 20
+const numeric *_num20_p;
+const ex _ex20 = ex(*_num20_p);
+
+// static numeric 24
+const numeric *_num24_p;
+const ex _ex24 = ex(*_num24_p);
+
+// static numeric 25
+const numeric *_num25_p;
+const ex _ex25 = ex(*_num25_p);
+
+// static numeric 30
+const numeric *_num30_p;
+const ex _ex30 = ex(*_num30_p);
+
+// static numeric 48
+const numeric *_num48_p;
+const ex _ex48 = ex(*_num48_p);
+
+// static numeric 60
+const numeric *_num60_p;
+const ex _ex60 = ex(*_num60_p);
+
+// static numeric 120
+const numeric *_num120_p;
+const ex _ex120 = ex(*_num120_p);
+
 // comment skeleton for header files
 
 
index a6e28d74ef6026c83a1ab90a9502b39940b82c74..e8ac1bd1a3c6585a838b965dfb7810b00ddc3927 100644 (file)
@@ -4,7 +4,7 @@
  *  of any interest to the user of the library. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -397,7 +397,7 @@ private:
        // Generates all distinct permutations of a multiset.
        // (Based on Aaron Williams' algorithm 1 from "Loopless Generation of
        // Multiset Permutations using a Constant Number of Variables by Prefix
-       // Shifts." <http://webhome.csc.uvic.ca/~haron/CoolMulti.pdf>)
+       // Shifts." <https://dl.acm.org/doi/pdf/10.5555/1496770.1496877>)
        struct coolmulti {
                // element of singly linked list
                struct element {
diff --git a/ginac/utils_multi_iterator.h b/ginac/utils_multi_iterator.h
new file mode 100644 (file)
index 0000000..443b12c
--- /dev/null
@@ -0,0 +1,1488 @@
+/** @file utils_multi_iterator.h
+ *
+ *  Utilities for summing over multiple indices */
+
+/*
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef GINAC_UTILS_MULTI_ITERATOR_H
+#define GINAC_UTILS_MULTI_ITERATOR_H
+
+#include <cstddef>
+#include <vector>
+#include <ostream>
+#include <iterator>
+
+namespace GiNaC {
+
+/**
+ *
+ * SFINAE test for distance
+ *
+ */
+template <typename T> class has_distance {
+private:
+       typedef char yes_type[1];
+       typedef char no_type[2];
+
+       template <typename C> static yes_type & test( decltype(std::distance<C>) ) ;
+       template <typename C> static no_type & test(...);
+
+public:
+       enum { value = sizeof(test<T>(0)) == sizeof(yes_type) };
+};
+
+/**
+ *
+ * For printing a multi-index: 
+ * If the templates are used, where T is an iterator, printing the address where the iterator points to is not meaningful.
+ * However, we may print the difference to the starting point.
+ *
+ */
+template<typename T> typename std::enable_if<has_distance<T>::value, typename std::iterator_traits<T>::difference_type>::type format_index_value(const T & a, const T & b) {
+               return std::distance(a,b);
+}
+
+/**
+ *
+ * For all other cases we simply print the value.
+ *
+ */
+template<typename T> typename std::enable_if<!has_distance<T>::value, T>::type format_index_value(const T & a, const T & b) {
+       return b;
+}
+
+/**
+ *
+ * basic_multi_iterator is a base class.
+ *
+ * The base class itself does not do anything useful.
+ * A typical use of a class derived from basic_multi_iterator is
+ *
+ *    multi_iterator_ordered<int> k(0,4,2);
+ *
+ *    for( k.init(); !k.overflow(); k++) {
+ *     std::cout << k << std::endl;
+ *    }
+ *
+ * which prints out 
+ *
+ *   multi_iterator_ordered(0,1)
+ *   multi_iterator_ordered(0,2)
+ *   multi_iterator_ordered(0,3)
+ *   multi_iterator_ordered(1,2)
+ *   multi_iterator_ordered(1,3)
+ *   multi_iterator_ordered(2,3)
+ *
+ * Individual components of k can be accessed with k[i] or k(i).
+ *
+ * All classes derived from basic_multi_iterator follow the same syntax.
+ *
+ */
+template<class T> class basic_multi_iterator {
+
+       // ctors
+public :  
+       basic_multi_iterator(void);
+       explicit basic_multi_iterator(T B, T N, size_t k);
+       explicit basic_multi_iterator(T B, T N, const std::vector<T> & vv);
+
+       // dtor 
+       virtual ~basic_multi_iterator();
+       // functions 
+public :
+       size_t size(void) const;
+       bool overflow(void) const;
+       const std::vector<T> & get_vector(void) const;
+
+       // subscripting
+public :  
+       T operator[](size_t i) const;
+       T & operator[](size_t i);
+
+       T operator()(size_t i) const;
+       T & operator()(size_t i);
+
+       // virtual functions
+public :  
+       // initialization
+       virtual basic_multi_iterator<T> & init(void);
+       // postfix increment
+       virtual basic_multi_iterator<T> & operator++ (int);
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const basic_multi_iterator<TT> & v);
+
+       // member variables :
+protected : 
+       T N;
+       T B;
+       std::vector<T> v;
+       bool flag_overflow;
+
+};
+
+/**
+ *
+ * The class multi_iterator_ordered defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ *     B \le i_j < N
+ * \f]
+ * and
+ * \f[
+ *     i_j < i_{j+1}.
+ * \f]
+ * It is assumed that \f$k>0\f$ and \f$ N-B \ge k \f$.
+ * 
+ */
+template<class T> class multi_iterator_ordered : public basic_multi_iterator<T> {
+
+       // ctors
+public :  
+       multi_iterator_ordered(void);
+       explicit multi_iterator_ordered(T B, T N, size_t k);
+       explicit multi_iterator_ordered(T B, T N, const std::vector<T> & vv);
+
+       // overriding virtual functions from base class
+public :  
+       // initialization
+       basic_multi_iterator<T> & init(void);
+       // postfix increment
+       basic_multi_iterator<T> & operator++ (int);
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered<TT> & v);
+
+};
+
+/**
+ *
+ * The class multi_iterator_ordered_eq defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ *     B \le i_j < N
+ * \f]
+ * and
+ * \f[
+ *     i_j \le i_{j+1}.
+ * \f]
+ * It is assumed that \f$k>0\f$.
+ * 
+ */
+template<class T> class multi_iterator_ordered_eq : public basic_multi_iterator<T> {
+
+       // ctors
+public :  
+       multi_iterator_ordered_eq(void);
+       explicit multi_iterator_ordered_eq(T B, T N, size_t k);
+       explicit multi_iterator_ordered_eq(T B, T N, const std::vector<T> & vv);
+
+       // overriding virtual functions from base class
+public :  
+       // initialization
+       basic_multi_iterator<T> & init(void);
+       // postfix increment
+       basic_multi_iterator<T> & operator++ (int);
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered_eq<TT> & v);
+
+};
+
+/**
+ *
+ * The class multi_iterator_ordered_eq_indv defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ *     B \le i_j < N_j
+ * \f]
+ * and
+ * \f[
+ *     i_j \le i_{j+1}.
+ * \f]
+ * 
+ */
+template<class T> class multi_iterator_ordered_eq_indv : public basic_multi_iterator<T> {
+
+       // ctors
+public :  
+       multi_iterator_ordered_eq_indv(void);
+       explicit multi_iterator_ordered_eq_indv(T B, const std::vector<T> & Nv, size_t k);
+       explicit multi_iterator_ordered_eq_indv(T B, const std::vector<T> & Nv, const std::vector<T> & vv);
+
+       // overriding virtual functions from base class
+public :  
+       // initialization
+       basic_multi_iterator<T> & init(void);
+       // postfix increment
+       basic_multi_iterator<T> & operator++ (int);
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered_eq_indv<TT> & v);
+
+       // member variables :
+protected : 
+       std::vector<T> Nv;
+};
+
+/**
+ *
+ * The class multi_iterator_counter defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ *     B \le i_j < N
+ * \f]
+ * 
+ */
+template<class T> class multi_iterator_counter : public basic_multi_iterator<T> {
+
+       // ctors
+public :  
+       multi_iterator_counter(void);
+       explicit multi_iterator_counter(T B, T N, size_t k);
+       explicit multi_iterator_counter(T B, T N, const std::vector<T> & vv);
+
+       // overriding virtual functions from base class
+public :  
+       // initialization
+       basic_multi_iterator<T> & init(void);
+       // postfix increment
+       basic_multi_iterator<T> & operator++ (int);
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_counter<TT> & v);
+
+};
+
+/**
+ *
+ * The class multi_iterator_counter_indv defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ *     B \le i_j < N_j
+ * \f]
+ * 
+ */
+template<class T> class multi_iterator_counter_indv : public basic_multi_iterator<T> {
+
+       // ctors
+public :  
+       multi_iterator_counter_indv(void);
+       explicit multi_iterator_counter_indv(T B, const std::vector<T> & Nv, size_t k);
+       explicit multi_iterator_counter_indv(T B, const std::vector<T> & Nv, const std::vector<T> & vv);
+
+       // overriding virtual functions from base class
+public :  
+       // initialization
+       basic_multi_iterator<T> & init(void);
+       // postfix increment
+       basic_multi_iterator<T> & operator++ (int);
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_counter_indv<TT> & v);
+
+       // member variables :
+protected : 
+       std::vector<T> Nv;
+};
+
+/**
+ *
+ * The class multi_iterator_permutation defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, for which
+ * \f[
+ *    B \le i_j < N
+ * \f]
+ * and
+ * \f[
+ *     i_i \neq i_j
+ * \f]
+ * In particular, if \f$N-B=k\f$, multi_iterator_permutation loops over all
+ * permutations of \f$k\f$ elements.
+ * 
+ */
+template<class T> class multi_iterator_permutation : public basic_multi_iterator<T> {
+
+       // ctors
+public :  
+       multi_iterator_permutation(void);
+       explicit multi_iterator_permutation(T B, T N, size_t k);
+       explicit multi_iterator_permutation(T B, T N, const std::vector<T> & vv);
+
+       // overriding virtual functions from base class
+public :  
+       // initialization
+       basic_multi_iterator<T> & init(void);
+       // postfix increment
+       basic_multi_iterator<T> & operator++ (int);
+
+       // new functions in this class
+       int get_sign(void) const;
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_permutation<TT> & v);
+
+};
+
+/**
+ *
+ * The class multi_iterator_shuffle defines a multi_iterator,
+ * which runs over all shuffles of a and b.
+ * 
+ */
+template<class T> class multi_iterator_shuffle : public basic_multi_iterator<T> {
+
+       // ctors
+public :  
+       multi_iterator_shuffle(void);
+       explicit multi_iterator_shuffle(const std::vector<T> & a, const std::vector<T> & b);
+
+       // overriding virtual functions from base class
+public :  
+       // initialization
+       basic_multi_iterator<T> & init(void);
+       // postfix increment
+       basic_multi_iterator<T> & operator++ (int);
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_shuffle<TT> & v);
+
+       // member variables :
+protected : 
+       size_t N_internal;
+       std::vector<size_t> v_internal;
+       std::vector<T> v_orig;
+};
+
+/**
+ *
+ * The class multi_iterator_shuffle_prime defines a multi_iterator,
+ * which runs over all shuffles of a and b, excluding the first one (a,b).
+ * 
+ */
+template<class T> class multi_iterator_shuffle_prime : public multi_iterator_shuffle<T> {
+
+       // ctors
+public :  
+       multi_iterator_shuffle_prime(void);
+       explicit multi_iterator_shuffle_prime(const std::vector<T> & a, const std::vector<T> & b);
+
+       // overriding virtual functions from base class
+public :  
+       // initialization
+       basic_multi_iterator<T> & init(void);
+       // I/O operators
+       template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_shuffle_prime<TT> & v);
+};
+
+// ----------------------------------------------------------------------------------------------------------------
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline basic_multi_iterator<T>::basic_multi_iterator(void) : N(), B(), v(), flag_overflow(false)
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N, lower limit B and size k .
+ *
+ */
+template<class T> inline basic_multi_iterator<T>::basic_multi_iterator(T BB, T NN, size_t k) : N(NN), B(BB), v(k), flag_overflow(false)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline basic_multi_iterator<T>::basic_multi_iterator(T BB, T NN, const std::vector<T> & vv) : N(NN), B(BB), v(vv), flag_overflow(false)
+{}
+
+/**
+ *
+ * Destructor
+ *
+ */
+template<class T> inline basic_multi_iterator<T>::~basic_multi_iterator()
+{}
+
+// functions 
+
+/**
+ *
+ * Returns the size of a multi_iterator.
+ *
+ */
+template<class T> inline size_t basic_multi_iterator<T>::size(void) const
+{
+       return v.size();
+}
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ *    (n_1,n_2,n_3,...,n_k) = (B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & basic_multi_iterator<T>::init(void) 
+{
+       flag_overflow = false;
+
+       for ( size_t i=0; i<v.size(); i++) {
+               v[i] = B;
+       }
+       return *this;
+}
+
+/**
+ *
+ * Return the overflow flag.
+ *
+ */
+template<class T> inline bool basic_multi_iterator<T>::overflow(void) const
+{
+       return flag_overflow;
+}
+
+/**
+ *
+ * Returns a reference to the vector v.
+ *
+ */
+template<class T> inline const std::vector<T> & basic_multi_iterator<T>::get_vector(void) const
+{
+       return v;
+}
+
+// subscripting
+
+/**
+ *
+ * Subscription via []
+ *
+ */
+template<class T> inline T basic_multi_iterator<T>::operator[](size_t i) const
+{
+       return v[i];
+}
+
+/**
+ *
+ * Subscription via []
+ *
+ */
+template<class T> inline T & basic_multi_iterator<T>::operator[](size_t i)
+{
+       return v[i];
+}
+
+/**
+ *
+ * Subscription via ()
+ *
+ */
+template<class T> inline T basic_multi_iterator<T>::operator()(size_t i) const
+{
+       return v[i];
+}
+
+/**
+ *
+ * Subscription via ()
+ *
+ */
+template<class T> inline T & basic_multi_iterator<T>::operator()(size_t i)
+{
+       return v[i];
+}
+
+
+/**
+ *
+ * No effect for basic_multi_iterator
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & basic_multi_iterator<T>::operator++ (int)
+{
+       return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator prints out as 
+ * basic_multi_iterator(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const basic_multi_iterator<T> & v)
+{
+       os << "basic_multi_iterator(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+       
+       return os << ")";
+}
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_ordered<T>::multi_iterator_ordered(void) : basic_multi_iterator<T>()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_ordered<T>::multi_iterator_ordered(T B, T N, size_t k) : basic_multi_iterator<T>(B,N,k)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_ordered<T>::multi_iterator_ordered(T B, T N, const std::vector<T> & v) : basic_multi_iterator<T>(B,N,v)
+{}
+
+// functions 
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ *    (n_1,n_2,n_3,...,n_k) = (B+0,B+1,B+2,...,B+k-1)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered<T>::init(void) 
+{
+       this->flag_overflow = false;
+       T it = this->B;
+
+       for ( size_t i=0; i < this->v.size(); i++) {
+               this->v[i] = it;
+               it++;
+       }
+       return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered<T>::operator++ (int)
+{
+       int k = this->size();
+       int j = k - 1;
+       T Upper_limit = this->N;
+
+       while ( j>0 ) {
+               this->v[j]++;
+               if ( this->v[j] == Upper_limit ) {
+                       j--;
+                       Upper_limit--;
+               }
+               else {
+                       break;
+               }
+       }
+
+       if (j==0) {
+               this->v[j]++;
+               if (this->v[j] == Upper_limit) this->flag_overflow=true;
+       }
+
+       if ( j>= 0) {
+               for (int jj=j+1;jj<k;jj++) {
+                       this->v[jj] = this->v[jj-1];
+                       this->v[jj]++;
+               }
+       }
+
+       return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_ordered prints out as 
+ * multi_iterator_ordered(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered<T> & v)
+{
+       os << "multi_iterator_ordered(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+
+       return os << ")";
+}
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq<T>::multi_iterator_ordered_eq(void) : basic_multi_iterator<T>()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq<T>::multi_iterator_ordered_eq(T B, T N, size_t k) : basic_multi_iterator<T>(B,N,k)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq<T>::multi_iterator_ordered_eq(T B, T N, const std::vector<T> & v) : basic_multi_iterator<T>(B,N,v)
+{}
+
+// functions 
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ *    (n_1,n_2,...,n_k) = (B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered_eq<T>::init(void) 
+{
+       this->flag_overflow = false;
+
+       for ( size_t i=0; i < this->v.size(); i++) {
+               this->v[i] = this->B;
+       }
+       return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered_eq<T>::operator++ (int)
+{
+       int k = this->size();
+       int j = k - 1;
+
+       while ( j>0 ) {
+               this->v[j]++;
+               if ( this->v[j] == this->N ) {
+                       j--;
+               }
+               else {
+                       break;
+               }
+       }
+
+       if (j==0) {
+               this->v[j]++;
+               if (this->v[j] == this->N) {
+                       this->flag_overflow=true;
+               }
+       }
+
+       if ( j>= 0) {
+               for (int jj=j+1;jj<k;jj++) {
+                       this->v[jj] = this->v[jj-1];
+               }
+       }
+
+       return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_ordered_eq prints out as 
+ * multi_iterator_ordered_eq(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered_eq<T> & v)
+{
+       os << "multi_iterator_ordered_eq(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+
+       return os << ")";
+}
+
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq_indv<T>::multi_iterator_ordered_eq_indv(void) : basic_multi_iterator<T>(), Nv()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq_indv<T>::multi_iterator_ordered_eq_indv(T B, const std::vector<T> & Nvv, size_t k) : basic_multi_iterator<T>(B,B,k), Nv(Nvv)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq_indv<T>::multi_iterator_ordered_eq_indv(T B, const std::vector<T> & Nvv, const std::vector<T> & v) : basic_multi_iterator<T>(B,B,v), Nv(Nvv)
+{}
+
+// functions 
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ *    (n_1,n_2,n_3,...,n_k) = (B,B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered_eq_indv<T>::init(void) 
+{
+       this->flag_overflow = false;
+
+       for ( size_t i=0; i < this->v.size(); i++) {
+               this->v[i] = this->B;
+       }
+       return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered_eq_indv<T>::operator++ (int)
+{
+       int k = this->size();
+       int j = k - 1;
+
+       while ( j>0 ) {
+               this->v[j]++;
+               if ( this->v[j] == Nv[j] ) {
+                       j--;
+               }
+               else {
+                       break;
+               }
+       }
+
+       if (j==0) {
+               this->v[j]++;
+               if (this->v[j] == Nv[j]) {
+                       this->flag_overflow=true;
+               }
+       }
+
+       if ( j>= 0) {
+               for (int jj=j+1;jj<k;jj++) {
+                       this->v[jj] = this->v[jj-1];
+               }
+       }
+
+       return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_ordered_eq_indv prints out as 
+ * multi_iterator_ordered_eq_indv(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered_eq_indv<T> & v)
+{
+       os << "multi_iterator_ordered_eq_indv(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+
+       return os << ")";
+}
+
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_counter<T>::multi_iterator_counter(void) : basic_multi_iterator<T>()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_counter<T>::multi_iterator_counter(T B, T N, size_t k) : basic_multi_iterator<T>(B,N,k)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_counter<T>::multi_iterator_counter(T B, T N, const std::vector<T> & v) : basic_multi_iterator<T>(B,N,v)
+{}
+
+// functions 
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ *    (n_1,n_2,n_3,...,n_k) = (B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_counter<T>::init(void) 
+{
+       this->flag_overflow = false;
+
+       for ( size_t i=0; i < this->v.size(); i++) {
+               this->v[i] = this->B;
+       }
+       return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_counter<T>::operator++ (int)
+{
+       int k = this->size();
+       int j = k - 1;
+
+       while ( j>0 ) {
+               this->v[j]++;
+               if ( this->v[j] == this->N ) {
+                       this->v[j] = this->B;
+                       j--;
+               }
+               else {
+                       break;
+               }
+       }
+
+       if (j==0) {
+               this->v[j]++;
+               if (this->v[j] == this->N) {
+                       this->v[j] = this->B;
+                       this->flag_overflow=true;
+               }
+       }
+
+       return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_counter prints out as 
+ * multi_iterator_counter(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_counter<T> & v)
+{
+       os << "multi_iterator_counter(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+
+       return os << ")";
+}
+
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_counter_indv<T>::multi_iterator_counter_indv(void) : basic_multi_iterator<T>(), Nv()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_counter_indv<T>::multi_iterator_counter_indv(T B, const std::vector<T> & Nvv, size_t k) : basic_multi_iterator<T>(B,B,k), Nv(Nvv)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_counter_indv<T>::multi_iterator_counter_indv(T B, const std::vector<T> & Nvv, const std::vector<T> & v) : basic_multi_iterator<T>(B,B,v), Nv(Nvv)
+{}
+
+// functions 
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ *    (n_1,n_2,n_3,...,n_k) = (B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_counter_indv<T>::init(void) 
+{
+       this->flag_overflow = false;
+
+       for ( size_t i=0; i < this->v.size(); i++) {
+               this->v[i] = this->B;
+       }
+       return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_counter_indv<T>::operator++ (int)
+{
+       int k = this->size();
+       int j = k - 1;
+
+       while ( j>0 ) {
+               this->v[j]++;
+               if ( this->v[j] == Nv[j] ) {
+                       this->v[j] = this->B;
+                       j--;
+               }
+               else {
+                       break;
+               }
+       }
+
+       if (j==0) {
+               this->v[j]++;
+               if (this->v[j] == Nv[j]) {
+                       this->v[j] = this->B;
+                       this->flag_overflow=true;
+               }
+       }
+
+       return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_counter_indv prints out as 
+ * multi_iterator_counter_indv(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_counter_indv<T> & v)
+{
+       os << "multi_iterator_counter_indv(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+
+       return os << ")";
+}
+
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_permutation<T>::multi_iterator_permutation(void) : basic_multi_iterator<T>()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_permutation<T>::multi_iterator_permutation(T B, T N, size_t k) : basic_multi_iterator<T>(B,N,k)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_permutation<T>::multi_iterator_permutation(T B, T N, const std::vector<T> & v) : basic_multi_iterator<T>(B,N,v)
+{}
+
+// functions 
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ *    (n_1,n_2,n_3,...,n_k) = (B+0,B+1,B+2,...,B+k-1)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_permutation<T>::init(void) 
+{
+       this->flag_overflow = false;
+       T it = this->B;
+
+       for ( size_t i=0; i < this->v.size(); i++) {
+               this->v[i] = it;
+               it++;
+       }
+       return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_permutation<T>::operator++ (int)
+{
+       int k = this->size();
+       int j = k - 1;
+
+       while ( j>=0 ) {
+               bool flag_have_already = true;
+               while ( flag_have_already ) {
+                       this->v[j]++;
+
+                       // update flag_have_already
+                       flag_have_already = false;
+                       for (int ii=0; ii<j; ii++) {
+                               if (this->v[j] == this->v[ii]) {
+                                       flag_have_already = true;
+                               }
+                       }
+               }
+
+               if ( this->v[j] == this->N ) {
+                       j--;
+               }
+               else {
+                       break;
+               }
+       }
+
+       for (int l=j+1; l<k; l++) {
+               this->v[l] = this->B;
+
+               bool flag_have_already;
+               do {
+                       flag_have_already = false;
+                       for (int ii=0; ii<l; ii++) {
+                               if (this->v[l] == this->v[ii]) {
+                                       flag_have_already = true;
+                               }
+                       }
+                       if (flag_have_already) {
+                               this->v[l]++;
+                       }
+               }
+               while (flag_have_already);
+       }
+
+       // check for overflow
+       this->flag_overflow = true;
+       T it = this->B;
+       for (int ii=0; ii<k; ii++) {
+               if (this->v[ii] != it) {
+                       this->flag_overflow = false;
+               }
+               it++;
+       }
+
+       return *this;
+}
+
+/**
+ *
+ * Returns the sign of the permutation, defined by
+ * \f[
+ *     \left(-1\right)^{n_{inv}},
+ * \f]
+ * where \f$ n_{inv} \f$ is the number of inversions, e.g. the
+ * number of pairs \f$ i < j \f$ for which
+ * \f[
+ *     n_i > n_j.
+ * \f]
+ *     
+ */
+template<class T> inline int multi_iterator_permutation<T>::get_sign() const
+{
+       int sign = 1;
+       int k = this->size();
+
+       for ( int i=0; i<k; i++) {
+               for ( int j=i+1; j<k; j++) {
+                       // works only for random-access iterators
+                       if ( this->v[i] > this->v[j] ) {
+                               sign = -sign;
+                       }
+               }
+       }
+
+       return sign;
+}
+
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_permutation prints out as 
+ * multi_iterator_permutation(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_permutation<T> & v)
+{
+       os << "multi_iterator_permutation(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+
+       return os << ")";
+}
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_shuffle<T>::multi_iterator_shuffle(void) : basic_multi_iterator<T>(), N_internal(), v_internal(), v_orig()
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_shuffle<T>::multi_iterator_shuffle(const std::vector<T> & a, const std::vector<T> & b) : basic_multi_iterator<T>(), N_internal(), v_internal(), v_orig()
+{
+       this->B = a[0];
+
+       for (size_t i=0; i<a.size(); i++) {
+               this->v.push_back( a[i] );
+               this->v_orig.push_back( a[i] );
+               this->v_internal.push_back( i );
+       }
+       for (size_t i=0; i<b.size(); i++) {
+               this->v.push_back( b[i] );
+               this->v_orig.push_back( b[i] );
+       }
+       this->N_internal = this->v.size();
+}
+
+// functions 
+
+/**
+ *
+ * Initialize the multi-index to the first shuffle.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_shuffle<T>::init(void) 
+{
+       this->flag_overflow = false;
+
+       for ( size_t i=0; i < this->v_internal.size(); i++) {
+               this->v_internal[i] = i;
+       }
+       for ( size_t i=0; i < this->v.size(); i++) {
+               this->v[i] = this->v_orig[i];
+       }
+       return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_shuffle<T>::operator++ (int)
+{
+       int k = this->v_internal.size();
+       int j = k - 1;
+       size_t Upper_limit = this->N_internal;
+
+       while ( j>0 ) {
+               this->v_internal[j]++;
+               if ( this->v_internal[j] == Upper_limit ) {
+                       j--;
+                       Upper_limit--;
+               }
+               else {
+                       break;
+               }
+       }
+
+       if (j==0) {
+               this->v_internal[j]++;
+               if (this->v_internal[j] == Upper_limit) {
+                       this->flag_overflow=true;
+               }
+       }
+
+       if ( j>= 0) {
+               for (int jj=j+1;jj<k;jj++) {
+                       this->v_internal[jj] = this->v_internal[jj-1];
+                       this->v_internal[jj]++;
+               }
+       }
+
+       // update v
+       if ( !(this->flag_overflow) ) {
+               size_t i_a = 0;
+               size_t i_b = 0;
+               size_t i_all = 0;
+               for (size_t j=0; j<k; j++) {
+                       for (size_t i=i_all; i < this->v_internal[j]; i++) {
+                               this->v[i_all] = this->v_orig[k+i_b];
+                               i_b++;
+                               i_all++;
+                       }
+                       this->v[i_all] = this->v_orig[i_a];
+                       i_a++;
+                       i_all++;
+               }
+               for (size_t i = this->v_internal[k-1]+1; i < this->v.size(); i++) {
+                       this->v[i_all] = this->v_orig[k+i_b];
+                       i_b++;
+                       i_all++;
+               }
+       }
+
+       return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_shuffle prints out as 
+ * multi_iterator_shuffle(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_shuffle<T> & v)
+{
+       os << "multi_iterator_shuffle(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+
+       return os << ")";
+}
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_shuffle_prime<T>::multi_iterator_shuffle_prime(void) : multi_iterator_shuffle<T>()
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_shuffle_prime<T>::multi_iterator_shuffle_prime(const std::vector<T> & a, const std::vector<T> & b) : multi_iterator_shuffle<T>(a,b)
+{}
+
+// functions 
+
+/**
+ *
+ * Initialize the multi-index to the first shuffle.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_shuffle_prime<T>::init(void) 
+{
+       this->flag_overflow = false;
+
+       for ( size_t i=0; i < this->v_internal.size(); i++) {
+               this->v_internal[i] = i;
+       }
+       for ( size_t i=0; i < this->v.size(); i++) {
+               this->v[i] = this->v_orig[i];
+       }
+
+       (*this)++;
+
+       return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_shuffle_prime prints out as 
+ * multi_iterator_shuffle_prime(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_shuffle_prime<T> & v)
+{
+       os << "multi_iterator_shuffle_prime(";
+       for ( size_t i=0; i<v.size(); i++) {
+               if (i>0) {
+                       os << ",";
+               }
+               os << format_index_value(v.B,v(i));
+       }
+
+       return os << ")";
+}
+
+} // namespace GiNaC
+
+#endif // ndef GINAC_UTILS_MULTI_ITERATOR_H
index 9048fc366ce55b5ffa2b2c9405ecbf13b0a82dd3..d6c1381bbf2040de7b67e031ea99d9bea77730de 100644 (file)
@@ -3,7 +3,7 @@
  *  GiNaC library version information. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #define GINACLIB_MAJOR_VERSION 1
 
 /* Minor version of GiNaC */
-#define GINACLIB_MINOR_VERSION 7
+#define GINACLIB_MINOR_VERSION 8
 
 /* Micro version of GiNaC */
-#define GINACLIB_MICRO_VERSION 6
+#define GINACLIB_MICRO_VERSION 7
 
 // GiNaC library version information. It has very little to do with GiNaC
 // version number. In particular, library version is OS dependent. 
 // increasing. This doesn't matter, though: there is not incurred cost
 // for numbers that are omitted, except for shrinking the available space
 // of leftover numbers. Not something we need to worry about yet. ;-)
-// TODO, when setting GINAC_LT_REVISION to 0:
+//
+// On Linux, the SONAME is libginac.so.$(GINAC_LT_CURRENT)-$(GINAC_LT_AGE).
+//
+// TODO, when breaking the SONAME:
 //  * change matrix inverse to use default argument (twice)
-//  * remove interfaces marked as deprecated
-#define GINAC_LT_CURRENT  10
-#define GINAC_LT_REVISION 0
-#define GINAC_LT_AGE      4
+//  * check for interfaces marked as deprecated
+#define GINAC_LT_CURRENT  12
+#define GINAC_LT_REVISION 6
+#define GINAC_LT_AGE      1
 
 /*
  * GiNaC archive file version information.
index cdfa2ab475f84a5898ff7b72c197a59349b6d4cf..4512c87e1a9cdf3c059bb0c5ccd8faba77af41ea 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's wildcard objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 2dc547a4d4493d3dfa0c276c5ed20f31a5a07a7c..34d0c5e7250f46ae92cbec576e0b7f9f0b239224 100644 (file)
@@ -3,7 +3,7 @@
  *  Interface to GiNaC's wildcard objects. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/ginsh/.gitignore b/ginsh/.gitignore
new file mode 100644 (file)
index 0000000..c3ba366
--- /dev/null
@@ -0,0 +1,7 @@
+ginsh
+ginsh.1
+ginsh_parser.cpp
+ginsh_parser.hpp
+ginsh_lexer.cpp
+ginsh_op_help.h
+ginsh_fcn_help.h
index 9f4c0a8f8ea1f4bf659abb16f60b39163ea8ade4..d90dd8e13c6ee5922aa857aee98f7b6d774a98fe 100644 (file)
@@ -1,9 +1,3 @@
-include_directories(
-       ${CMAKE_CURRENT_SOURCE_DIR}/../ginac
-       ${CMAKE_CURRENT_BINARY_DIR}/../ginac
-       ${CMAKE_CURRENT_SOURCE_DIR}
-       ${CMAKE_CURRENT_BINARY_DIR})
-add_definitions(-DIN_GINAC)
 
 bison_target(ginsh_parser
              ginsh_parser.ypp
@@ -34,19 +28,20 @@ set(ginsh_DISTRIB
     ginsh_fcn_help.py
     ginsh_op_help.py
 )
+set(ginsh_include_directories ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
 if (READLINE_FOUND)
-       include_directories(${READLINE_INCLUDE_DIRS})
+       set(ginsh_include_directories ${ginsh_include_directories} ${READLINE_INCLUDE_DIRS})
 endif()
 
 add_custom_command(
        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ginsh_fcn_help.h
-       COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_fcn_help.py -o ginsh_fcn_help.h ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in
+       COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_fcn_help.py -o ginsh_fcn_help.h ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in
        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_fcn_help.py
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
 
 add_custom_command(
        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ginsh_op_help.h
-       COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_op_help.py -o ginsh_op_help.h ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in
+       COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_op_help.py -o ginsh_op_help.h ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in
        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_op_help.py
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
 
@@ -61,5 +56,7 @@ if (READLINE_FOUND)
 endif()
 
 add_executable(ginsh ${ginsh_SOURCES} ${ginsh_HEADERS})
-target_link_libraries(ginsh ginac ${ginsh_extra_libs} ${LIBDL_LIBRARIES})
-install(TARGETS ginsh RUNTIME DESTINATION "${BIN_INSTALL_DIR}")
+target_link_libraries(ginsh ginac::ginac ${ginsh_extra_libs})
+target_include_directories(ginsh PRIVATE ${ginsh_include_directories})
+target_compile_definitions(ginsh PRIVATE HAVE_CONFIG_H)
+install(TARGETS ginsh RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
index 4c1a65c881c9d0c076d0a61a043c99294996e725..e9ab0555da22714904a16bbd6db8a5d55e9726e5 100644 (file)
@@ -368,12 +368,18 @@ detail here. Please refer to the GiNaC documentation.
 .BI series( expression ", " relation-or-symbol ", " order )
 \- series expansion
 .br
+.BI series_to_poly( series )
+\- convert a series into a polynomial by dropping the Order() term
+.br
 .BI sprem( expression ", " expression ", " symbol )
 \- sparse pseudo-remainder of polynomials
 .br
 .BI sqrfree( "expression [" ", " symbol-list] )
 \- square-free factorization of a polynomial
 .br
+.BI sqrfree_parfrac( expression ", " symbol )
+\- square-free partial fraction decomposition of rational function
+.br
 .BI sqrt( expression )
 \- square root
 .br
@@ -520,22 +526,14 @@ must be of a certain type (e.g. a symbol, or a list). The first argument has
 number 0, the second argument number 1, etc.
 .SH AUTHOR
 .TP
-The GiNaC Group:
-.br
-Christian Bauer <Christian.Bauer@uni-mainz.de>
-.br
-Alexander Frink <Alexander.Frink@uni-mainz.de>
-.br
-Richard Kreckel <Richard.Kreckel@uni-mainz.de>
-.br
-Jens Vollinga <vollinga@thep.physik.uni-mainz.de>
+The GiNaC maintainers <https://www.ginac.de/>.
 .SH SEE ALSO
 GiNaC Tutorial \- An open framework for symbolic computation within the
 C++ programming language
 .PP
 CLN \- A Class Library for Numbers, Bruno Haible
 .SH COPYRIGHT
-Copyright \(co 1999-2019 Johannes Gutenberg Universit\(:at Mainz, Germany
+Copyright \(co 1999-2024 Johannes Gutenberg Universit\(:at Mainz, Germany
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index 74cb28b924b79fc2b20c9a6d138c5d20d29dc48e..0decd3cd89bc117065254b2a3a3ace59604ad157 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Global definitions for ginsh.
  *
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -29,8 +29,6 @@
 #include <iostream>
 #include <string>
 
-using namespace std;
-
 #ifdef HAVE_READLINE_READLINE_H
 extern "C" {
 #include <readline/readline.h>
@@ -49,10 +47,8 @@ extern "C" {
 #include <ginac/ginac.h>
 #endif
 
-using namespace GiNaC;
-
 // yacc stack type
-#define YYSTYPE ex
+#define YYSTYPE GiNaC::ex
 
 // lex functions/variables
 extern int yyerror(const char *s);
@@ -65,7 +61,7 @@ extern int num_files;
 extern char **file_list;
 
 // Table of all used symbols
-typedef map<string, ex> sym_tab;
+typedef std::map<std::string, GiNaC::ex> sym_tab;
 extern sym_tab syms;
 
 // Type of symbols to generate (real or complex)
index 486d4347486785f3f496f2bb68807a0192271f55..6c00a6c9a2f551a02239f538454af2fa2834d8f7 100644 (file)
@@ -5,7 +5,7 @@
  *  functions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
old mode 100755 (executable)
new mode 100644 (file)
index 1c7ea49..edc675b
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+
 # encoding: utf-8
 # Convert help for ginsh functions from man page to C source
 import sys, re, optparse
index 6f6ea7e602d9021d6cfa776309c044d380d37499..449ce6b5c44234dbab7ca977d6142313f9abb36d 100644 (file)
@@ -4,7 +4,7 @@
  *  This file must be processed with flex. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -38,6 +38,9 @@
 #include "ginsh.h"
 #include "ginsh_parser.hpp"
 
+using namespace std;
+using namespace GiNaC;
+
 #define YY_INPUT(buf, result, max_size) (result = ginsh_input(buf, max_size))
 
 // Table of all used symbols
@@ -200,8 +203,16 @@ static int ginsh_input(char *buf, int max_size)
                        YY_FATAL_ERROR("input in flex scanner failed");
                result = n;
 #endif
-       } else if (((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin))
-               YY_FATAL_ERROR("input in flex scanner failed");
+       } else {
+               int c = '*', n;
+               for (n = 0; n < max_size && (c = getc(yyin)) != EOF && c != '\n'; ++n)
+                       buf[n] = (char)c;
+               if (c == '\n')
+                       buf[n++] = (char)c;
+               if (c == EOF && ferror(yyin))
+                       YY_FATAL_ERROR("input in flex scanner failed");
+               result = n;
+       }
 
        return result;
 }
old mode 100755 (executable)
new mode 100644 (file)
index f093257..a38697f
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+
 # encoding: utf-8
 # Convert help for ginsh operators from man page to C source
 import sys, re, optparse
index ed43cc4a1bbcd262eee6d2d85ee7de8eba16bb5b..a142f4bba25109c139b50b33284dac2d8afd9e6d 100644 (file)
@@ -4,7 +4,7 @@
  *  This file must be processed with yacc/bison. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -45,6 +45,9 @@
 
 #include "ginsh.h"
 
+using namespace std;
+using namespace GiNaC;
+
 #define YYERROR_VERBOSE 1
 
 #ifdef HAVE_LIBREADLINE
@@ -439,7 +442,7 @@ static ex f_integer_content(const exprseq &e)
 static ex f_integral(const exprseq &e)
 {
        CHECK_ARG(0, symbol, integral);
-       return integral(e[0], e[1], e[2], e[3]);
+       return GiNaC::integral(e[0], e[1], e[2], e[3]);
 }
 
 static ex f_inverse(const exprseq &e)
@@ -527,6 +530,12 @@ static ex f_series(const exprseq &e)
        return e[0].series(e[1], ex_to<numeric>(e[2]).to_int());
 }
 
+static ex f_series_to_poly(const exprseq &e)
+{
+       CHECK_ARG(0, pseries, series_to_poly);
+       return series_to_poly(ex_to<pseries>(e[0]));
+}
+
 static ex f_sprem(const exprseq &e)
 {
        return sprem(e[0], e[1], e[2]);
@@ -538,6 +547,11 @@ static ex f_sqrfree2(const exprseq &e)
        return sqrfree(e[0], ex_to<lst>(e[1]));
 }
 
+static ex f_sqrfree_parfrac(const exprseq &e)
+{
+       return sqrfree_parfrac(e[0], ex_to<symbol>(e[1]));
+}
+
 static ex f_subs3(const exprseq &e)
 {
        CHECK_ARG(1, lst, subs);
@@ -571,6 +585,105 @@ static ex f_unit(const exprseq &e)
        return e[0].unit(e[1]);
 }
 
+static ex f_basic_log_kernel(const exprseq &e)
+{
+       return basic_log_kernel();      
+}
+
+static ex f_multiple_polylog_kernel(const exprseq &e)
+{
+       return multiple_polylog_kernel(e[0]);   
+}
+
+static ex f_ELi_kernel(const exprseq &e)
+{
+       return ELi_kernel(e[0],e[1],e[2],e[3]); 
+}
+
+static ex f_Ebar_kernel(const exprseq &e)
+{
+       return Ebar_kernel(e[0],e[1],e[2],e[3]);        
+}
+
+static ex f_Kronecker_dtau_kernel_4(const exprseq &e)
+{
+       return Kronecker_dtau_kernel(e[0],e[1],e[2],e[3]);      
+}
+
+static ex f_Kronecker_dtau_kernel_3(const exprseq &e)
+{
+       return Kronecker_dtau_kernel(e[0],e[1],e[2]);   
+}
+
+static ex f_Kronecker_dtau_kernel_2(const exprseq &e)
+{
+       return Kronecker_dtau_kernel(e[0],e[1]);        
+}
+
+static ex f_Kronecker_dz_kernel_5(const exprseq &e)
+{
+       return Kronecker_dz_kernel(e[0],e[1],e[2],e[3],e[4]);   
+}
+
+static ex f_Kronecker_dz_kernel_4(const exprseq &e)
+{
+       return Kronecker_dz_kernel(e[0],e[1],e[2],e[3]);        
+}
+
+static ex f_Kronecker_dz_kernel_3(const exprseq &e)
+{
+       return Kronecker_dz_kernel(e[0],e[1],e[2]);     
+}
+
+static ex f_Eisenstein_kernel_6(const exprseq &e)
+{
+       return Eisenstein_kernel(e[0],e[1],e[2],e[3],e[4],e[5]);        
+}
+
+static ex f_Eisenstein_kernel_5(const exprseq &e)
+{
+       return Eisenstein_kernel(e[0],e[1],e[2],e[3],e[4]);     
+}
+
+static ex f_Eisenstein_h_kernel_5(const exprseq &e)
+{
+       return Eisenstein_h_kernel(e[0],e[1],e[2],e[3],e[4]);   
+}
+
+static ex f_Eisenstein_h_kernel_4(const exprseq &e)
+{
+       return Eisenstein_h_kernel(e[0],e[1],e[2],e[3]);        
+}
+
+static ex f_modular_form_kernel_3(const exprseq &e)
+{
+       return modular_form_kernel(e[0],e[1],e[2]);     
+}
+
+static ex f_modular_form_kernel_2(const exprseq &e)
+{
+       return modular_form_kernel(e[0],e[1]);  
+}
+
+static ex f_user_defined_kernel(const exprseq &e)
+{
+       return user_defined_kernel(e[0],e[1]);  
+}
+
+static ex f_q_expansion_modular_form(const exprseq &e)
+{
+       if ( is_a<Eisenstein_kernel>(e[0]) ) {
+               return ex_to<Eisenstein_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int());
+       }       
+       if ( is_a<Eisenstein_h_kernel>(e[0]) ) {
+               return ex_to<Eisenstein_h_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int());
+       }       
+       if ( is_a<modular_form_kernel>(e[0]) ) {
+               return ex_to<modular_form_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int());
+       }       
+       throw(std::invalid_argument("first argument must be a modular form"));
+}
+
 static ex f_dummy(const exprseq &e)
 {
        throw(std::logic_error("dummy function called (shouldn't happen)"));
@@ -635,9 +748,11 @@ static const fcn_init builtin_fcns[] = {
        {"rem", f_rem, 3},
        {"resultant", f_resultant, 3},
        {"series", f_series, 3},
+       {"series_to_poly", f_series_to_poly, 1},
        {"sprem", f_sprem, 3},
        {"sqrfree", f_sqrfree1, 1},
        {"sqrfree", f_sqrfree2, 2},
+       {"sqrfree_parfrac", f_sqrfree_parfrac, 2},
        {"sqrt", f_sqrt, 1},
        {"subs", f_subs2, 2},
        {"subs", f_subs3, 3},
@@ -647,6 +762,24 @@ static const fcn_init builtin_fcns[] = {
        {"transpose", f_transpose, 1},
        {"unassign", f_unassign, 1},
        {"unit", f_unit, 2},
+       {"basic_log_kernel", f_basic_log_kernel, 0},
+       {"multiple_polylog_kernel", f_multiple_polylog_kernel, 1},
+       {"ELi_kernel", f_ELi_kernel, 4},
+       {"Ebar_kernel", f_Ebar_kernel, 4},
+       {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_4, 4},
+       {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_3, 3},
+       {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_2, 2},
+       {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_5, 5},
+       {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_4, 4},
+       {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_3, 3},
+       {"Eisenstein_kernel", f_Eisenstein_kernel_6, 6},
+       {"Eisenstein_kernel", f_Eisenstein_kernel_5, 5},
+       {"Eisenstein_h_kernel", f_Eisenstein_h_kernel_5, 5},
+       {"Eisenstein_h_kernel", f_Eisenstein_h_kernel_4, 4},
+       {"modular_form_kernel", f_modular_form_kernel_3, 3},
+       {"modular_form_kernel", f_modular_form_kernel_2, 2},
+       {"user_defined_kernel", f_user_defined_kernel, 2},
+       {"q_expansion_modular_form", f_q_expansion_modular_form, 3},
        {nullptr, f_dummy, 0}        // End marker
 };
 
@@ -678,11 +811,15 @@ static const fcn_help_init builtin_help[] = {
        {"tan", "tangent function"},
        {"tanh", "hyperbolic tangent function"},
        {"zeta", "zeta function\nzeta(x) is Riemann's zeta function, zetaderiv(n,x) its nth derivative.\nIf x is a GiNaC::lst, it is a multiple zeta value\nzeta(x,s) is an alternating Euler sum"},
+       {"G", "multiple polylogarithm (integral representation)"},
        {"Li2", "dilogarithm"},
        {"Li3", "trilogarithm"},
        {"Li", "(multiple) polylogarithm"},
        {"S", "Nielsen's generalized polylogarithm"},
        {"H", "harmonic polylogarithm"},
+       {"EllipticK", "complete elliptic integral of the first kind"},
+       {"EllipticE", "complete elliptic integral of the second kind"},
+       {"iterated_integral", "iterated integral"},
        {"Order", "order term function (for truncated power series)"},
        {"Derivative", "inert differential operator"},
        {nullptr, nullptr}  // End marker
@@ -876,7 +1013,7 @@ static void ginsh_readline_init(char* name)
 void greeting(void)
 {
     cout << "ginsh - GiNaC Interactive Shell (GiNaC V" << GINACLIB_VERSION << ")" << endl;
-    cout << "  __,  _______  Copyright (C) 1999-2019 Johannes Gutenberg University Mainz,\n"
+    cout << "  __,  _______  Copyright (C) 1999-2024 Johannes Gutenberg University Mainz,\n"
          << " (__) *       | Germany.  This is free software with ABSOLUTELY NO WARRANTY.\n"
          << "  ._) i N a C | You are welcome to redistribute it under certain conditions.\n"
          << "<-------------' For details type `warranty;'.\n" << endl;
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644 (file)
index 0000000..38066dd
--- /dev/null
@@ -0,0 +1,5 @@
+libtool.m4
+ltoptions.m4
+ltsugar.m4
+ltversion.m4
+lt~obsolete.m4
index 9e9eaedaaad3b9dd97db1f88f780cbafd0d02936..8edf5152ec7a91bea5858436ae70bb6e877689a4 100644 (file)
 #
 #   Check for baseline language coverage in the compiler for the specified
 #   version of the C++ standard.  If necessary, add switches to CXX and
-#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)
-#   or '14' (for the C++14 standard).
+#   CXXCPP to enable support.  VERSION may be '11', '14', '17', or '20' for
+#   the respective C++ standard version.
 #
 #   The second argument, if specified, indicates whether you insist on an
 #   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
 #   -std=c++11).  If neither is specified, you get whatever works, with
-#   preference for an extended mode.
+#   preference for no added switch, and then for an extended mode.
 #
 #   The third argument, if specified 'mandatory' or if left unspecified,
 #   indicates that baseline support for the specified C++ standard is
 #   Copyright (c) 2015 Paul Norman <penorman@mac.com>
 #   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
 #   Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
+#   Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
+#   Copyright (c) 2020 Jason Merrill <jason@redhat.com>
+#   Copyright (c) 2021 Jörn Heusipp <osmanx@problemloesungsmaschine.de>
 #
 #   Copying and distribution of this file, with or without modification, are
 #   permitted in any medium without royalty provided the copyright notice
 #   and this notice are preserved.  This file is offered as-is, without any
 #   warranty.
 
-#serial 10
+#serial 18
 
 dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
 dnl  (serial version number 13).
@@ -49,6 +52,7 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
   m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
         [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
         [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+        [$1], [20], [ax_cxx_compile_alternatives="20"],
         [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
   m4_if([$2], [], [],
         [$2], [ext], [],
@@ -61,6 +65,16 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
   AC_LANG_PUSH([C++])dnl
   ac_success=no
 
+  m4_if([$2], [], [dnl
+    AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+                  ax_cv_cxx_compile_cxx$1,
+      [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+        [ax_cv_cxx_compile_cxx$1=yes],
+        [ax_cv_cxx_compile_cxx$1=no])])
+    if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+      ac_success=yes
+    fi])
+
   m4_if([$2], [noext], [], [dnl
   if test x$ac_success = xno; then
     for alternative in ${ax_cxx_compile_alternatives}; do
@@ -90,9 +104,18 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
     dnl HP's aCC needs +std=c++11 according to:
     dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
     dnl Cray's crayCC needs "-h std=c++11"
+    dnl MSVC needs -std:c++NN for C++17 and later (default is C++14)
     for alternative in ${ax_cxx_compile_alternatives}; do
-      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
-        cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do
+        if test x"$switch" = xMSVC; then
+          dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide
+          dnl with -std=c++17.  We suffix the cache variable name with _MSVC to
+          dnl avoid this.
+          switch=-std:c++${alternative}
+          cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC])
+        else
+          cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+        fi
         AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
                        $cachevar,
           [ac_save_CXX="$CXX"
@@ -139,7 +162,6 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
   _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
 )
 
-
 dnl  Test body for checking C++14 support
 
 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
@@ -147,12 +169,24 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
   _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
 )
 
+dnl  Test body for checking C++17 support
+
 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
   _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
   _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
   _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
 )
 
+dnl  Test body for checking C++20 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_20
+)
+
+
 dnl  Tests for new features in C++11
 
 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
@@ -164,7 +198,11 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
 
 #error "This is not a C++ compiler"
 
-#elif __cplusplus < 201103L
+// MSVC always sets __cplusplus to 199711L in older versions; newer versions
+// only set it correctly if /Zc:__cplusplus is specified as well as a
+// /std:c++NN switch:
+// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
+#elif __cplusplus < 201103L && !defined _MSC_VER
 
 #error "This is not a C++11 compiler"
 
@@ -189,11 +227,13 @@ namespace cxx11
 
     struct Base
     {
+      virtual ~Base() {}
       virtual void f() {}
     };
 
     struct Derived : public Base
     {
+      virtual ~Derived() override {}
       virtual void f() override {}
     };
 
@@ -453,7 +493,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
 
 #error "This is not a C++ compiler"
 
-#elif __cplusplus < 201402L
+#elif __cplusplus < 201402L && !defined _MSC_VER
 
 #error "This is not a C++14 compiler"
 
@@ -577,7 +617,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
 
 #error "This is not a C++ compiler"
 
-#elif __cplusplus < 201703L
+#elif __cplusplus < 201703L && !defined _MSC_VER
 
 #error "This is not a C++17 compiler"
 
@@ -943,6 +983,36 @@ namespace cxx17
 
 }  // namespace cxx17
 
-#endif  // __cplusplus < 201703L
+#endif  // __cplusplus < 201703L && !defined _MSC_VER
+
+]])
+
+
+dnl  Tests for new features in C++20
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 202002L && !defined _MSC_VER
+
+#error "This is not a C++20 compiler"
+
+#else
+
+#include <version>
+
+namespace cxx20
+{
+
+// As C++20 supports feature test macros in the standard, there is no
+// immediate need to actually test for feature availability on the
+// Autoconf side.
+
+}  // namespace cxx20
+
+#endif  // __cplusplus < 202002L && !defined _MSC_VER
 
 ]])
diff --git a/m4/host-cpu-c-abi.m4 b/m4/host-cpu-c-abi.m4
new file mode 100644 (file)
index 0000000..134f228
--- /dev/null
@@ -0,0 +1,678 @@
+# host-cpu-c-abi.m4 serial 15
+dnl Copyright (C) 2002-2023 Free Software Foundation, Inc.
+dnl This file 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 From Bruno Haible and Sam Steingold.
+
+dnl Sets the HOST_CPU variable to the canonical name of the CPU.
+dnl Sets the HOST_CPU_C_ABI variable to the canonical name of the CPU with its
+dnl C language ABI (application binary interface).
+dnl Also defines __${HOST_CPU}__ and __${HOST_CPU_C_ABI}__ as C macros in
+dnl config.h.
+dnl
+dnl This canonical name can be used to select a particular assembly language
+dnl source file that will interoperate with C code on the given host.
+dnl
+dnl For example:
+dnl * 'i386' and 'sparc' are different canonical names, because code for i386
+dnl   will not run on SPARC CPUs and vice versa. They have different
+dnl   instruction sets.
+dnl * 'sparc' and 'sparc64' are different canonical names, because code for
+dnl   'sparc' and code for 'sparc64' cannot be linked together: 'sparc' code
+dnl   contains 32-bit instructions, whereas 'sparc64' code contains 64-bit
+dnl   instructions. A process on a SPARC CPU can be in 32-bit mode or in 64-bit
+dnl   mode, but not both.
+dnl * 'mips' and 'mipsn32' are different canonical names, because they use
+dnl   different argument passing and return conventions for C functions, and
+dnl   although the instruction set of 'mips' is a large subset of the
+dnl   instruction set of 'mipsn32'.
+dnl * 'mipsn32' and 'mips64' are different canonical names, because they use
+dnl   different sizes for the C types like 'int' and 'void *', and although
+dnl   the instruction sets of 'mipsn32' and 'mips64' are the same.
+dnl * The same canonical name is used for different endiannesses. You can
+dnl   determine the endianness through preprocessor symbols:
+dnl   - 'arm': test __ARMEL__.
+dnl   - 'mips', 'mipsn32', 'mips64': test _MIPSEB vs. _MIPSEL.
+dnl   - 'powerpc64': test _BIG_ENDIAN vs. _LITTLE_ENDIAN.
+dnl * The same name 'i386' is used for CPUs of type i386, i486, i586
+dnl   (Pentium), AMD K7, Pentium II, Pentium IV, etc., because
+dnl   - Instructions that do not exist on all of these CPUs (cmpxchg,
+dnl     MMX, SSE, SSE2, 3DNow! etc.) are not frequently used. If your
+dnl     assembly language source files use such instructions, you will
+dnl     need to make the distinction.
+dnl   - Speed of execution of the common instruction set is reasonable across
+dnl     the entire family of CPUs. If you have assembly language source files
+dnl     that are optimized for particular CPU types (like GNU gmp has), you
+dnl     will need to make the distinction.
+dnl   See <https://en.wikipedia.org/wiki/X86_instruction_listings>.
+AC_DEFUN([gl_HOST_CPU_C_ABI],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_REQUIRE([gl_C_ASM])
+  AC_CACHE_CHECK([host CPU and C ABI], [gl_cv_host_cpu_c_abi],
+    [case "$host_cpu" in
+
+changequote(,)dnl
+       i[34567]86 )
+changequote([,])dnl
+         gl_cv_host_cpu_c_abi=i386
+         ;;
+
+       x86_64 )
+         # On x86_64 systems, the C compiler may be generating code in one of
+         # these ABIs:
+         # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64.
+         # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64
+         #   with native Windows (mingw, MSVC).
+         # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32.
+         # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#if (defined __x86_64__ || defined __amd64__ \
+                     || defined _M_X64 || defined _M_AMD64)
+                 int ok;
+                #else
+                 error fail
+                #endif
+              ]])],
+           [AC_COMPILE_IFELSE(
+              [AC_LANG_SOURCE(
+                 [[#if defined __ILP32__ || defined _ILP32
+                    int ok;
+                   #else
+                    error fail
+                   #endif
+                 ]])],
+              [gl_cv_host_cpu_c_abi=x86_64-x32],
+              [gl_cv_host_cpu_c_abi=x86_64])],
+           [gl_cv_host_cpu_c_abi=i386])
+         ;;
+
+changequote(,)dnl
+       alphaev[4-8] | alphaev56 | alphapca5[67] | alphaev6[78] )
+changequote([,])dnl
+         gl_cv_host_cpu_c_abi=alpha
+         ;;
+
+       arm* | aarch64 )
+         # Assume arm with EABI.
+         # On arm64 systems, the C compiler may be generating code in one of
+         # these ABIs:
+         # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64.
+         # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32.
+         # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#ifdef __aarch64__
+                 int ok;
+                #else
+                 error fail
+                #endif
+              ]])],
+           [AC_COMPILE_IFELSE(
+              [AC_LANG_SOURCE(
+                [[#if defined __ILP32__ || defined _ILP32
+                   int ok;
+                  #else
+                   error fail
+                  #endif
+                ]])],
+              [gl_cv_host_cpu_c_abi=arm64-ilp32],
+              [gl_cv_host_cpu_c_abi=arm64])],
+           [# Don't distinguish little-endian and big-endian arm, since they
+            # don't require different machine code for simple operations and
+            # since the user can distinguish them through the preprocessor
+            # defines __ARMEL__ vs. __ARMEB__.
+            # But distinguish arm which passes floating-point arguments and
+            # return values in integer registers (r0, r1, ...) - this is
+            # gcc -mfloat-abi=soft or gcc -mfloat-abi=softfp - from arm which
+            # passes them in float registers (s0, s1, ...) and double registers
+            # (d0, d1, ...) - this is gcc -mfloat-abi=hard. GCC 4.6 or newer
+            # sets the preprocessor defines __ARM_PCS (for the first case) and
+            # __ARM_PCS_VFP (for the second case), but older GCC does not.
+            echo 'double ddd; void func (double dd) { ddd = dd; }' > conftest.c
+            # Look for a reference to the register d0 in the .s file.
+            AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $gl_c_asm_opt conftest.c) >/dev/null 2>&1
+            if LC_ALL=C grep 'd0,' conftest.$gl_asmext >/dev/null; then
+              gl_cv_host_cpu_c_abi=armhf
+            else
+              gl_cv_host_cpu_c_abi=arm
+            fi
+            rm -f conftest*
+           ])
+         ;;
+
+       hppa1.0 | hppa1.1 | hppa2.0* | hppa64 )
+         # On hppa, the C compiler may be generating 32-bit code or 64-bit
+         # code. In the latter case, it defines _LP64 and __LP64__.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#ifdef __LP64__
+                 int ok;
+                #else
+                 error fail
+                #endif
+              ]])],
+           [gl_cv_host_cpu_c_abi=hppa64],
+           [gl_cv_host_cpu_c_abi=hppa])
+         ;;
+
+       ia64* )
+         # On ia64 on HP-UX, the C compiler may be generating 64-bit code or
+         # 32-bit code. In the latter case, it defines _ILP32.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#ifdef _ILP32
+                 int ok;
+                #else
+                 error fail
+                #endif
+              ]])],
+           [gl_cv_host_cpu_c_abi=ia64-ilp32],
+           [gl_cv_host_cpu_c_abi=ia64])
+         ;;
+
+       mips* )
+         # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this
+         # at 32.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64)
+                 int ok;
+                #else
+                 error fail
+                #endif
+              ]])],
+           [gl_cv_host_cpu_c_abi=mips64],
+           [# In the n32 ABI, _ABIN32 is defined, _ABIO32 is not defined (but
+            # may later get defined by <sgidefs.h>), and _MIPS_SIM == _ABIN32.
+            # In the 32 ABI, _ABIO32 is defined, _ABIN32 is not defined (but
+            # may later get defined by <sgidefs.h>), and _MIPS_SIM == _ABIO32.
+            AC_COMPILE_IFELSE(
+              [AC_LANG_SOURCE(
+                 [[#if (_MIPS_SIM == _ABIN32)
+                    int ok;
+                   #else
+                    error fail
+                   #endif
+                 ]])],
+              [gl_cv_host_cpu_c_abi=mipsn32],
+              [gl_cv_host_cpu_c_abi=mips])])
+         ;;
+
+       powerpc* )
+         # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD.
+         # No need to distinguish them here; the caller may distinguish
+         # them based on the OS.
+         # On powerpc64 systems, the C compiler may still be generating
+         # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may
+         # be generating 64-bit code.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#if defined __powerpc64__ || defined __LP64__
+                 int ok;
+                #else
+                 error fail
+                #endif
+              ]])],
+           [# On powerpc64, there are two ABIs on Linux: The AIX compatible
+            # one and the ELFv2 one. The latter defines _CALL_ELF=2.
+            AC_COMPILE_IFELSE(
+              [AC_LANG_SOURCE(
+                 [[#if defined _CALL_ELF && _CALL_ELF == 2
+                    int ok;
+                   #else
+                    error fail
+                   #endif
+                 ]])],
+              [gl_cv_host_cpu_c_abi=powerpc64-elfv2],
+              [gl_cv_host_cpu_c_abi=powerpc64])
+           ],
+           [gl_cv_host_cpu_c_abi=powerpc])
+         ;;
+
+       rs6000 )
+         gl_cv_host_cpu_c_abi=powerpc
+         ;;
+
+       riscv32 | riscv64 )
+         # There are 2 architectures (with variants): rv32* and rv64*.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#if __riscv_xlen == 64
+                  int ok;
+                #else
+                  error fail
+                #endif
+              ]])],
+           [cpu=riscv64],
+           [cpu=riscv32])
+         # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d.
+         # Size of 'long' and 'void *':
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#if defined __LP64__
+                  int ok;
+                #else
+                  error fail
+                #endif
+              ]])],
+           [main_abi=lp64],
+           [main_abi=ilp32])
+         # Float ABIs:
+         # __riscv_float_abi_double:
+         #   'float' and 'double' are passed in floating-point registers.
+         # __riscv_float_abi_single:
+         #   'float' are passed in floating-point registers.
+         # __riscv_float_abi_soft:
+         #   No values are passed in floating-point registers.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#if defined __riscv_float_abi_double
+                  int ok;
+                #else
+                  error fail
+                #endif
+              ]])],
+           [float_abi=d],
+           [AC_COMPILE_IFELSE(
+              [AC_LANG_SOURCE(
+                 [[#if defined __riscv_float_abi_single
+                     int ok;
+                   #else
+                     error fail
+                   #endif
+                 ]])],
+              [float_abi=f],
+              [float_abi=''])
+           ])
+         gl_cv_host_cpu_c_abi="${cpu}-${main_abi}${float_abi}"
+         ;;
+
+       s390* )
+         # On s390x, the C compiler may be generating 64-bit (= s390x) code
+         # or 31-bit (= s390) code.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#if defined __LP64__ || defined __s390x__
+                  int ok;
+                #else
+                  error fail
+                #endif
+              ]])],
+           [gl_cv_host_cpu_c_abi=s390x],
+           [gl_cv_host_cpu_c_abi=s390])
+         ;;
+
+       sparc | sparc64 )
+         # UltraSPARCs running Linux have `uname -m` = "sparc64", but the
+         # C compiler still generates 32-bit code.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE(
+              [[#if defined __sparcv9 || defined __arch64__
+                 int ok;
+                #else
+                 error fail
+                #endif
+              ]])],
+           [gl_cv_host_cpu_c_abi=sparc64],
+           [gl_cv_host_cpu_c_abi=sparc])
+         ;;
+
+       *)
+         gl_cv_host_cpu_c_abi="$host_cpu"
+         ;;
+     esac
+    ])
+
+  dnl In most cases, $HOST_CPU and $HOST_CPU_C_ABI are the same.
+  HOST_CPU=`echo "$gl_cv_host_cpu_c_abi" | sed -e 's/-.*//'`
+  HOST_CPU_C_ABI="$gl_cv_host_cpu_c_abi"
+  AC_SUBST([HOST_CPU])
+  AC_SUBST([HOST_CPU_C_ABI])
+
+  # This was
+  #   AC_DEFINE_UNQUOTED([__${HOST_CPU}__])
+  #   AC_DEFINE_UNQUOTED([__${HOST_CPU_C_ABI}__])
+  # earlier, but KAI C++ 3.2d doesn't like this.
+  sed -e 's/-/_/g' >> confdefs.h <<EOF
+#ifndef __${HOST_CPU}__
+#define __${HOST_CPU}__ 1
+#endif
+#ifndef __${HOST_CPU_C_ABI}__
+#define __${HOST_CPU_C_ABI}__ 1
+#endif
+EOF
+  AH_TOP([/* CPU and C ABI indicator */
+#ifndef __i386__
+#undef __i386__
+#endif
+#ifndef __x86_64_x32__
+#undef __x86_64_x32__
+#endif
+#ifndef __x86_64__
+#undef __x86_64__
+#endif
+#ifndef __alpha__
+#undef __alpha__
+#endif
+#ifndef __arm__
+#undef __arm__
+#endif
+#ifndef __armhf__
+#undef __armhf__
+#endif
+#ifndef __arm64_ilp32__
+#undef __arm64_ilp32__
+#endif
+#ifndef __arm64__
+#undef __arm64__
+#endif
+#ifndef __hppa__
+#undef __hppa__
+#endif
+#ifndef __hppa64__
+#undef __hppa64__
+#endif
+#ifndef __ia64_ilp32__
+#undef __ia64_ilp32__
+#endif
+#ifndef __ia64__
+#undef __ia64__
+#endif
+#ifndef __loongarch64__
+#undef __loongarch64__
+#endif
+#ifndef __m68k__
+#undef __m68k__
+#endif
+#ifndef __mips__
+#undef __mips__
+#endif
+#ifndef __mipsn32__
+#undef __mipsn32__
+#endif
+#ifndef __mips64__
+#undef __mips64__
+#endif
+#ifndef __powerpc__
+#undef __powerpc__
+#endif
+#ifndef __powerpc64__
+#undef __powerpc64__
+#endif
+#ifndef __powerpc64_elfv2__
+#undef __powerpc64_elfv2__
+#endif
+#ifndef __riscv32__
+#undef __riscv32__
+#endif
+#ifndef __riscv64__
+#undef __riscv64__
+#endif
+#ifndef __riscv32_ilp32__
+#undef __riscv32_ilp32__
+#endif
+#ifndef __riscv32_ilp32f__
+#undef __riscv32_ilp32f__
+#endif
+#ifndef __riscv32_ilp32d__
+#undef __riscv32_ilp32d__
+#endif
+#ifndef __riscv64_ilp32__
+#undef __riscv64_ilp32__
+#endif
+#ifndef __riscv64_ilp32f__
+#undef __riscv64_ilp32f__
+#endif
+#ifndef __riscv64_ilp32d__
+#undef __riscv64_ilp32d__
+#endif
+#ifndef __riscv64_lp64__
+#undef __riscv64_lp64__
+#endif
+#ifndef __riscv64_lp64f__
+#undef __riscv64_lp64f__
+#endif
+#ifndef __riscv64_lp64d__
+#undef __riscv64_lp64d__
+#endif
+#ifndef __s390__
+#undef __s390__
+#endif
+#ifndef __s390x__
+#undef __s390x__
+#endif
+#ifndef __sh__
+#undef __sh__
+#endif
+#ifndef __sparc__
+#undef __sparc__
+#endif
+#ifndef __sparc64__
+#undef __sparc64__
+#endif
+])
+
+])
+
+
+dnl Sets the HOST_CPU_C_ABI_32BIT variable to 'yes' if the C language ABI
+dnl (application binary interface) is a 32-bit one, to 'no' if it is a 64-bit
+dnl one, or to 'unknown' if unknown.
+dnl This is a simplified variant of gl_HOST_CPU_C_ABI.
+AC_DEFUN([gl_HOST_CPU_C_ABI_32BIT],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_CACHE_CHECK([32-bit host C ABI], [gl_cv_host_cpu_c_abi_32bit],
+    [if test -n "$gl_cv_host_cpu_c_abi"; then
+       case "$gl_cv_host_cpu_c_abi" in
+         i386 | x86_64-x32 | arm | armhf | arm64-ilp32 | hppa | ia64-ilp32 | mips | mipsn32 | powerpc | riscv*-ilp32* | s390 | sparc)
+           gl_cv_host_cpu_c_abi_32bit=yes ;;
+         x86_64 | alpha | arm64 | hppa64 | ia64 | mips64 | powerpc64 | powerpc64-elfv2 | riscv*-lp64* | s390x | sparc64 )
+           gl_cv_host_cpu_c_abi_32bit=no ;;
+         *)
+           gl_cv_host_cpu_c_abi_32bit=unknown ;;
+       esac
+     else
+       case "$host_cpu" in
+
+         # CPUs that only support a 32-bit ABI.
+         arc \
+         | bfin \
+         | cris* \
+         | csky \
+         | epiphany \
+         | ft32 \
+         | h8300 \
+         | m68k \
+         | microblaze | microblazeel \
+         | nds32 | nds32le | nds32be \
+         | nios2 | nios2eb | nios2el \
+         | or1k* \
+         | or32 \
+         | sh | sh[1234] | sh[1234]e[lb] \
+         | tic6x \
+         | xtensa* )
+           gl_cv_host_cpu_c_abi_32bit=yes
+           ;;
+
+         # CPUs that only support a 64-bit ABI.
+changequote(,)dnl
+         alpha | alphaev[4-8] | alphaev56 | alphapca5[67] | alphaev6[78] \
+         | mmix )
+changequote([,])dnl
+           gl_cv_host_cpu_c_abi_32bit=no
+           ;;
+
+changequote(,)dnl
+         i[34567]86 )
+changequote([,])dnl
+           gl_cv_host_cpu_c_abi_32bit=yes
+           ;;
+
+         x86_64 )
+           # On x86_64 systems, the C compiler may be generating code in one of
+           # these ABIs:
+           # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64.
+           # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64
+           #   with native Windows (mingw, MSVC).
+           # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32.
+           # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386.
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#if (defined __x86_64__ || defined __amd64__ \
+                       || defined _M_X64 || defined _M_AMD64) \
+                      && !(defined __ILP32__ || defined _ILP32)
+                   int ok;
+                  #else
+                   error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=no],
+             [gl_cv_host_cpu_c_abi_32bit=yes])
+           ;;
+
+         arm* | aarch64 )
+           # Assume arm with EABI.
+           # On arm64 systems, the C compiler may be generating code in one of
+           # these ABIs:
+           # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64.
+           # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32.
+           # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf.
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#if defined __aarch64__ && !(defined __ILP32__ || defined _ILP32)
+                   int ok;
+                  #else
+                   error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=no],
+             [gl_cv_host_cpu_c_abi_32bit=yes])
+           ;;
+
+         hppa1.0 | hppa1.1 | hppa2.0* | hppa64 )
+           # On hppa, the C compiler may be generating 32-bit code or 64-bit
+           # code. In the latter case, it defines _LP64 and __LP64__.
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#ifdef __LP64__
+                   int ok;
+                  #else
+                   error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=no],
+             [gl_cv_host_cpu_c_abi_32bit=yes])
+           ;;
+
+         ia64* )
+           # On ia64 on HP-UX, the C compiler may be generating 64-bit code or
+           # 32-bit code. In the latter case, it defines _ILP32.
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#ifdef _ILP32
+                   int ok;
+                  #else
+                   error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=yes],
+             [gl_cv_host_cpu_c_abi_32bit=no])
+           ;;
+
+         mips* )
+           # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this
+           # at 32.
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64)
+                   int ok;
+                  #else
+                   error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=no],
+             [gl_cv_host_cpu_c_abi_32bit=yes])
+           ;;
+
+         powerpc* )
+           # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD.
+           # No need to distinguish them here; the caller may distinguish
+           # them based on the OS.
+           # On powerpc64 systems, the C compiler may still be generating
+           # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may
+           # be generating 64-bit code.
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#if defined __powerpc64__ || defined __LP64__
+                   int ok;
+                  #else
+                   error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=no],
+             [gl_cv_host_cpu_c_abi_32bit=yes])
+           ;;
+
+         rs6000 )
+           gl_cv_host_cpu_c_abi_32bit=yes
+           ;;
+
+         riscv32 | riscv64 )
+           # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d.
+           # Size of 'long' and 'void *':
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#if defined __LP64__
+                    int ok;
+                  #else
+                    error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=no],
+             [gl_cv_host_cpu_c_abi_32bit=yes])
+           ;;
+
+         s390* )
+           # On s390x, the C compiler may be generating 64-bit (= s390x) code
+           # or 31-bit (= s390) code.
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#if defined __LP64__ || defined __s390x__
+                    int ok;
+                  #else
+                    error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=no],
+             [gl_cv_host_cpu_c_abi_32bit=yes])
+           ;;
+
+         sparc | sparc64 )
+           # UltraSPARCs running Linux have `uname -m` = "sparc64", but the
+           # C compiler still generates 32-bit code.
+           AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE(
+                [[#if defined __sparcv9 || defined __arch64__
+                   int ok;
+                  #else
+                   error fail
+                  #endif
+                ]])],
+             [gl_cv_host_cpu_c_abi_32bit=no],
+             [gl_cv_host_cpu_c_abi_32bit=yes])
+           ;;
+
+         *)
+           gl_cv_host_cpu_c_abi_32bit=unknown
+           ;;
+       esac
+     fi
+    ])
+
+  HOST_CPU_C_ABI_32BIT="$gl_cv_host_cpu_c_abi_32bit"
+])
index 91ca9117098c5b50974fad2350c79d6d326796c1..6bc1886f5359c0822eadfe614c124732cff2cb08 100644 (file)
@@ -1,5 +1,5 @@
-# lib-ld.m4 serial 6
-dnl Copyright (C) 1996-2003, 2009-2015 Free Software Foundation, Inc.
+# lib-ld.m4 serial 10
+dnl Copyright (C) 1996-2003, 2009-2023 Free Software Foundation, Inc.
 dnl This file 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.
@@ -47,73 +47,122 @@ if test "${PATH_SEPARATOR+set}" != set; then
        }
 fi
 
-ac_prog=ld
-if test "$GCC" = yes; then
-  # Check if gcc -print-prog-name=ld gives a path.
+if test -n "$LD"; then
+  AC_MSG_CHECKING([for ld])
+elif test "$GCC" = yes; then
   AC_MSG_CHECKING([for ld used by $CC])
-  case $host in
-  *-*-mingw*)
-    # gcc leaves a trailing carriage return which upsets mingw
-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
-  *)
-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
-  esac
-  case $ac_prog in
-    # Accept absolute paths.
-    [[\\/]]* | ?:[[\\/]]*)
-      re_direlt='/[[^/]][[^/]]*/\.\./'
-      # Canonicalize the pathname of ld
-      ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'`
-      while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do
-        ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
-      done
-      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([acl_cv_path_LD],
-[if test -z "$LD"; then
-  acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-  for ac_dir in $PATH; do
-    IFS="$acl_save_ifs"
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      acl_cv_path_LD="$ac_dir/$ac_prog"
-      # Check to see if the program is GNU ld.  I'd rather use --version,
-      # but apparently some variants of GNU ld only accept -v.
-      # Break only if it was the GNU/non-GNU ld that we prefer.
-      case `"$acl_cv_path_LD" -v 2>&1 </dev/null` in
-      *GNU* | *'with BFD'*)
-        test "$with_gnu_ld" != no && break
-        ;;
-      *)
-        test "$with_gnu_ld" != yes && break
-        ;;
+if test -n "$LD"; then
+  # Let the user override the test with a path.
+  :
+else
+  AC_CACHE_VAL([acl_cv_path_LD],
+  [
+    acl_cv_path_LD= # Final result of this test
+    ac_prog=ld # Program to search in $PATH
+    if test "$GCC" = yes; then
+      # Check if gcc -print-prog-name=ld gives a path.
+      case $host in
+        *-*-mingw*)
+          # gcc leaves a trailing carriage return which upsets mingw
+          acl_output=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+        *)
+          acl_output=`($CC -print-prog-name=ld) 2>&5` ;;
+      esac
+      case $acl_output in
+        # Accept absolute paths.
+        [[\\/]]* | ?:[[\\/]]*)
+          re_direlt='/[[^/]][[^/]]*/\.\./'
+          # Canonicalize the pathname of ld
+          acl_output=`echo "$acl_output" | sed 's%\\\\%/%g'`
+          while echo "$acl_output" | grep "$re_direlt" > /dev/null 2>&1; do
+            acl_output=`echo $acl_output | sed "s%$re_direlt%/%"`
+          done
+          # Got the pathname. No search in PATH is needed.
+          acl_cv_path_LD="$acl_output"
+          ac_prog=
+          ;;
+        "")
+          # If it fails, then pretend we aren't using GCC.
+          ;;
+        *)
+          # If it is relative, then search for the first ld in PATH.
+          with_gnu_ld=unknown
+          ;;
       esac
     fi
-  done
-  IFS="$acl_save_ifs"
-else
-  acl_cv_path_LD="$LD" # Let the user override the test with a path.
-fi])
-LD="$acl_cv_path_LD"
+    if test -n "$ac_prog"; then
+      # Search for $ac_prog in $PATH.
+      acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+      for ac_dir in $PATH; do
+        IFS="$acl_save_ifs"
+        test -z "$ac_dir" && ac_dir=.
+        if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+          acl_cv_path_LD="$ac_dir/$ac_prog"
+          # Check to see if the program is GNU ld.  I'd rather use --version,
+          # but apparently some variants of GNU ld only accept -v.
+          # Break only if it was the GNU/non-GNU ld that we prefer.
+          case `"$acl_cv_path_LD" -v 2>&1 </dev/null` in
+            *GNU* | *'with BFD'*)
+              test "$with_gnu_ld" != no && break
+              ;;
+            *)
+              test "$with_gnu_ld" != yes && break
+              ;;
+          esac
+        fi
+      done
+      IFS="$acl_save_ifs"
+    fi
+    case $host in
+      *-*-aix*)
+        AC_COMPILE_IFELSE(
+          [AC_LANG_SOURCE(
+             [[#if defined __powerpc64__ || defined __LP64__
+                int ok;
+               #else
+                error fail
+               #endif
+             ]])],
+          [# The compiler produces 64-bit code. Add option '-b64' so that the
+           # linker groks 64-bit object files.
+           case "$acl_cv_path_LD " in
+             *" -b64 "*) ;;
+             *) acl_cv_path_LD="$acl_cv_path_LD -b64" ;;
+           esac
+          ], [])
+        ;;
+      sparc64-*-netbsd*)
+        AC_COMPILE_IFELSE(
+          [AC_LANG_SOURCE(
+             [[#if defined __sparcv9 || defined __arch64__
+                int ok;
+               #else
+                error fail
+               #endif
+             ]])],
+          [],
+          [# The compiler produces 32-bit code. Add option '-m elf32_sparc'
+           # so that the linker groks 32-bit object files.
+           case "$acl_cv_path_LD " in
+             *" -m elf32_sparc "*) ;;
+             *) acl_cv_path_LD="$acl_cv_path_LD -m elf32_sparc" ;;
+           esac
+          ])
+        ;;
+    esac
+  ])
+  LD="$acl_cv_path_LD"
+fi
 if test -n "$LD"; then
   AC_MSG_RESULT([$LD])
 else
   AC_MSG_RESULT([no])
+  AC_MSG_ERROR([no acceptable ld found in \$PATH])
 fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
 AC_LIB_PROG_LD_GNU
 ])
index d8d5d1f0e12092ce60a31b8338ef18f7a4c4a014..5f8afae61a6a6093547ff10737765aa791fade0e 100644 (file)
@@ -1,12 +1,12 @@
-# lib-link.m4 serial 26 (gettext-0.18.2)
-dnl Copyright (C) 2001-2015 Free Software Foundation, Inc.
+# lib-link.m4 serial 33
+dnl Copyright (C) 2001-2023 Free Software Foundation, Inc.
 dnl This file 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 From Bruno Haible.
 
-AC_PREREQ([2.54])
+AC_PREREQ([2.61])
 
 dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
 dnl the libraries corresponding to explicit and implicit dependencies.
@@ -124,8 +124,8 @@ dnl   acl_hardcode_direct,
 dnl   acl_hardcode_minus_L.
 AC_DEFUN([AC_LIB_RPATH],
 [
-  dnl Tell automake >= 1.10 to complain if config.rpath is missing.
-  m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
+  dnl Complain if config.rpath is missing.
+  AC_REQUIRE_AUX_FILE([config.rpath])
   AC_REQUIRE([AC_PROG_CC])                dnl we use $CC, $GCC, $LDFLAGS
   AC_REQUIRE([AC_LIB_PROG_LD])            dnl we use $LD, $with_gnu_ld
   AC_REQUIRE([AC_CANONICAL_HOST])         dnl we use $host
@@ -187,17 +187,17 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
   pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-],
                                      [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])])
   pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])])
-  dnl Autoconf >= 2.61 supports dots in --with options.
-  pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[m4_translit(PACK,[.],[_])],PACK)])
   dnl By default, look in $includedir and $libdir.
   use_additional=yes
   AC_LIB_WITH_FINAL_PREFIX([
     eval additional_includedir=\"$includedir\"
     eval additional_libdir=\"$libdir\"
+    eval additional_libdir2=\"$exec_prefix/$acl_libdirstem2\"
+    eval additional_libdir3=\"$exec_prefix/$acl_libdirstem3\"
   ])
-  AC_ARG_WITH(P_A_C_K[-prefix],
-[[  --with-]]P_A_C_K[[-prefix[=DIR]  search for ]PACKLIBS[ in DIR/include and DIR/lib
-  --without-]]P_A_C_K[[-prefix     don't search for ]PACKLIBS[ in includedir and libdir]],
+  AC_ARG_WITH(PACK[-prefix],
+[[  --with-]]PACK[[-prefix[=DIR]  search for ]]PACKLIBS[[ in DIR/include and DIR/lib
+  --without-]]PACK[[-prefix     don't search for ]]PACKLIBS[[ in includedir and libdir]],
 [
     if test "X$withval" = "Xno"; then
       use_additional=no
@@ -206,19 +206,25 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
         AC_LIB_WITH_FINAL_PREFIX([
           eval additional_includedir=\"$includedir\"
           eval additional_libdir=\"$libdir\"
+          eval additional_libdir2=\"$exec_prefix/$acl_libdirstem2\"
+          eval additional_libdir3=\"$exec_prefix/$acl_libdirstem3\"
         ])
       else
         additional_includedir="$withval/include"
         additional_libdir="$withval/$acl_libdirstem"
-        if test "$acl_libdirstem2" != "$acl_libdirstem" \
-           && ! test -d "$withval/$acl_libdirstem"; then
-          additional_libdir="$withval/$acl_libdirstem2"
-        fi
+        additional_libdir2="$withval/$acl_libdirstem2"
+        additional_libdir3="$withval/$acl_libdirstem3"
       fi
     fi
 ])
+  if test "X$additional_libdir2" = "X$additional_libdir"; then
+    additional_libdir2=
+  fi
+  if test "X$additional_libdir3" = "X$additional_libdir"; then
+    additional_libdir3=
+  fi
   dnl Search the library and its dependencies in $additional_libdir and
-  dnl $LDFLAGS. Using breadth-first-seach.
+  dnl $LDFLAGS. Use breadth-first search.
   LIB[]NAME=
   LTLIB[]NAME=
   INC[]NAME=
@@ -272,48 +278,54 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
             shrext=
           fi
           if test $use_additional = yes; then
-            dir="$additional_libdir"
-            dnl The same code as in the loop below:
-            dnl First look for a shared library.
-            if test -n "$acl_shlibext"; then
-              if test -f "$dir/$libname$shrext"; then
-                found_dir="$dir"
-                found_so="$dir/$libname$shrext"
-              else
-                if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
-                  ver=`(cd "$dir" && \
-                        for f in "$libname$shrext".*; do echo "$f"; done \
-                        | sed -e "s,^$libname$shrext\\\\.,," \
-                        | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
-                        | sed 1q ) 2>/dev/null`
-                  if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
-                    found_dir="$dir"
-                    found_so="$dir/$libname$shrext.$ver"
+            for additional_libdir_variable in additional_libdir additional_libdir2 additional_libdir3; do
+              if test "X$found_dir" = "X"; then
+                eval dir=\$$additional_libdir_variable
+                if test -n "$dir"; then
+                  dnl The same code as in the loop below:
+                  dnl First look for a shared library.
+                  if test -n "$acl_shlibext"; then
+                    if test -f "$dir/$libname$shrext" && acl_is_expected_elfclass < "$dir/$libname$shrext"; then
+                      found_dir="$dir"
+                      found_so="$dir/$libname$shrext"
+                    else
+                      if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+                        ver=`(cd "$dir" && \
+                              for f in "$libname$shrext".*; do echo "$f"; done \
+                              | sed -e "s,^$libname$shrext\\\\.,," \
+                              | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+                              | sed 1q ) 2>/dev/null`
+                        if test -n "$ver" && test -f "$dir/$libname$shrext.$ver" && acl_is_expected_elfclass < "$dir/$libname$shrext.$ver"; then
+                          found_dir="$dir"
+                          found_so="$dir/$libname$shrext.$ver"
+                        fi
+                      else
+                        eval library_names=\"$acl_library_names_spec\"
+                        for f in $library_names; do
+                          if test -f "$dir/$f" && acl_is_expected_elfclass < "$dir/$f"; then
+                            found_dir="$dir"
+                            found_so="$dir/$f"
+                            break
+                          fi
+                        done
+                      fi
+                    fi
                   fi
-                else
-                  eval library_names=\"$acl_library_names_spec\"
-                  for f in $library_names; do
-                    if test -f "$dir/$f"; then
+                  dnl Then look for a static library.
+                  if test "X$found_dir" = "X"; then
+                    if test -f "$dir/$libname.$acl_libext" && ${AR-ar} -p "$dir/$libname.$acl_libext" | acl_is_expected_elfclass; then
                       found_dir="$dir"
-                      found_so="$dir/$f"
-                      break
+                      found_a="$dir/$libname.$acl_libext"
                     fi
-                  done
+                  fi
+                  if test "X$found_dir" != "X"; then
+                    if test -f "$dir/$libname.la"; then
+                      found_la="$dir/$libname.la"
+                    fi
+                  fi
                 fi
               fi
-            fi
-            dnl Then look for a static library.
-            if test "X$found_dir" = "X"; then
-              if test -f "$dir/$libname.$acl_libext"; then
-                found_dir="$dir"
-                found_a="$dir/$libname.$acl_libext"
-              fi
-            fi
-            if test "X$found_dir" != "X"; then
-              if test -f "$dir/$libname.la"; then
-                found_la="$dir/$libname.la"
-              fi
-            fi
+            done
           fi
           if test "X$found_dir" = "X"; then
             for x in $LDFLAGS $LTLIB[]NAME; do
@@ -323,7 +335,7 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
                   dir=`echo "X$x" | sed -e 's/^X-L//'`
                   dnl First look for a shared library.
                   if test -n "$acl_shlibext"; then
-                    if test -f "$dir/$libname$shrext"; then
+                    if test -f "$dir/$libname$shrext" && acl_is_expected_elfclass < "$dir/$libname$shrext"; then
                       found_dir="$dir"
                       found_so="$dir/$libname$shrext"
                     else
@@ -333,14 +345,14 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
                               | sed -e "s,^$libname$shrext\\\\.,," \
                               | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
                               | sed 1q ) 2>/dev/null`
-                        if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+                        if test -n "$ver" && test -f "$dir/$libname$shrext.$ver" && acl_is_expected_elfclass < "$dir/$libname$shrext.$ver"; then
                           found_dir="$dir"
                           found_so="$dir/$libname$shrext.$ver"
                         fi
                       else
                         eval library_names=\"$acl_library_names_spec\"
                         for f in $library_names; do
-                          if test -f "$dir/$f"; then
+                          if test -f "$dir/$f" && acl_is_expected_elfclass < "$dir/$f"; then
                             found_dir="$dir"
                             found_so="$dir/$f"
                             break
@@ -351,7 +363,7 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
                   fi
                   dnl Then look for a static library.
                   if test "X$found_dir" = "X"; then
-                    if test -f "$dir/$libname.$acl_libext"; then
+                    if test -f "$dir/$libname.$acl_libext" && ${AR-ar} -p "$dir/$libname.$acl_libext" | acl_is_expected_elfclass; then
                       found_dir="$dir"
                       found_a="$dir/$libname.$acl_libext"
                     fi
@@ -377,7 +389,8 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
               dnl standard /usr/lib.
               if test "$enable_rpath" = no \
                  || test "X$found_dir" = "X/usr/$acl_libdirstem" \
-                 || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then
+                 || test "X$found_dir" = "X/usr/$acl_libdirstem2" \
+                 || test "X$found_dir" = "X/usr/$acl_libdirstem3"; then
                 dnl No hardcoding is needed.
                 LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
               else
@@ -477,6 +490,13 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
                 fi
                 additional_includedir="$basedir/include"
                 ;;
+              */$acl_libdirstem3 | */$acl_libdirstem3/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem3/"'*$,,'`
+                if test "$name" = '$1'; then
+                  LIB[]NAME[]_PREFIX="$basedir"
+                fi
+                additional_includedir="$basedir/include"
+                ;;
             esac
             if test "X$additional_includedir" != "X"; then
               dnl Potentially add $additional_includedir to $INCNAME.
@@ -527,19 +547,21 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
               for dep in $dependency_libs; do
                 case "$dep" in
                   -L*)
-                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
-                    dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+                    dependency_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                    dnl Potentially add $dependency_libdir to $LIBNAME and $LTLIBNAME.
                     dnl But don't add it
                     dnl   1. if it's the standard /usr/lib,
                     dnl   2. if it's /usr/local/lib and we are using GCC on Linux,
                     dnl   3. if it's already present in $LDFLAGS or the already
                     dnl      constructed $LIBNAME,
                     dnl   4. if it doesn't exist as a directory.
-                    if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \
-                       && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then
+                    if test "X$dependency_libdir" != "X/usr/$acl_libdirstem" \
+                       && test "X$dependency_libdir" != "X/usr/$acl_libdirstem2" \
+                       && test "X$dependency_libdir" != "X/usr/$acl_libdirstem3"; then
                       haveit=
-                      if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \
-                         || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then
+                      if test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem" \
+                         || test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem2" \
+                         || test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem3"; then
                         if test -n "$GCC"; then
                           case $host_os in
                             linux* | gnu* | k*bsd*-gnu) haveit=yes;;
@@ -550,29 +572,29 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
                         haveit=
                         for x in $LDFLAGS $LIB[]NAME; do
                           AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
-                          if test "X$x" = "X-L$additional_libdir"; then
+                          if test "X$x" = "X-L$dependency_libdir"; then
                             haveit=yes
                             break
                           fi
                         done
                         if test -z "$haveit"; then
-                          if test -d "$additional_libdir"; then
-                            dnl Really add $additional_libdir to $LIBNAME.
-                            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+                          if test -d "$dependency_libdir"; then
+                            dnl Really add $dependency_libdir to $LIBNAME.
+                            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$dependency_libdir"
                           fi
                         fi
                         haveit=
                         for x in $LDFLAGS $LTLIB[]NAME; do
                           AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
-                          if test "X$x" = "X-L$additional_libdir"; then
+                          if test "X$x" = "X-L$dependency_libdir"; then
                             haveit=yes
                             break
                           fi
                         done
                         if test -z "$haveit"; then
-                          if test -d "$additional_libdir"; then
-                            dnl Really add $additional_libdir to $LTLIBNAME.
-                            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+                          if test -d "$dependency_libdir"; then
+                            dnl Really add $dependency_libdir to $LTLIBNAME.
+                            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$dependency_libdir"
                           fi
                         fi
                       fi
@@ -609,7 +631,20 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
                     ;;
                   -l*)
                     dnl Handle this in the next round.
-                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    dnl But on GNU systems, ignore -lc options, because
+                    dnl   - linking with libc is the default anyway,
+                    dnl   - linking with libc.a may produce an error
+                    dnl     "/usr/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie"
+                    dnl     or may produce an executable that always crashes, see
+                    dnl     <https://lists.gnu.org/archive/html/grep-devel/2020-09/msg00052.html>.
+                    dep=`echo "X$dep" | sed -e 's/^X-l//'`
+                    if test "X$dep" != Xc \
+                       || case $host_os in
+                            linux* | gnu* | k*bsd*-gnu) false ;;
+                            *)                          true ;;
+                          esac; then
+                      names_next_round="$names_next_round $dep"
+                    fi
                     ;;
                   *.la)
                     dnl Handle this in the next round. Throw away the .la's
@@ -670,7 +705,6 @@ AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
       LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
     done
   fi
-  popdef([P_A_C_K])
   popdef([PACKLIBS])
   popdef([PACKUP])
   popdef([PACK])
@@ -721,7 +755,8 @@ AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS],
           dir="$next"
           dnl No need to hardcode the standard /usr/lib.
           if test "X$dir" != "X/usr/$acl_libdirstem" \
-             && test "X$dir" != "X/usr/$acl_libdirstem2"; then
+             && test "X$dir" != "X/usr/$acl_libdirstem2" \
+             && test "X$dir" != "X/usr/$acl_libdirstem3"; then
             rpathdirs="$rpathdirs $dir"
           fi
           next=
@@ -731,7 +766,8 @@ AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS],
             -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'`
                  dnl No need to hardcode the standard /usr/lib.
                  if test "X$dir" != "X/usr/$acl_libdirstem" \
-                    && test "X$dir" != "X/usr/$acl_libdirstem2"; then
+                    && test "X$dir" != "X/usr/$acl_libdirstem2" \
+                    && test "X$dir" != "X/usr/$acl_libdirstem3"; then
                    rpathdirs="$rpathdirs $dir"
                  fi
                  next= ;;
index 0465f477c0498d8a85224bc7fc3f5a46aac291ca..aefe7f7124df24754adb4bc370b4b7cfa880ebb3 100644 (file)
@@ -1,18 +1,11 @@
-# lib-prefix.m4 serial 7 (gettext-0.18)
-dnl Copyright (C) 2001-2005, 2008-2015 Free Software Foundation, Inc.
+# lib-prefix.m4 serial 20
+dnl Copyright (C) 2001-2005, 2008-2023 Free Software Foundation, Inc.
 dnl This file 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 From Bruno Haible.
 
-dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
-dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
-dnl require excessive bracketing.
-ifdef([AC_HELP_STRING],
-[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
-[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
-
 dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
 dnl to access previously installed libraries. The basic assumption is that
 dnl a user will want packages to use other packages he previously installed
@@ -32,9 +25,9 @@ AC_DEFUN([AC_LIB_PREFIX],
     eval additional_includedir=\"$includedir\"
     eval additional_libdir=\"$libdir\"
   ])
-  AC_LIB_ARG_WITH([lib-prefix],
-[  --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
-  --without-lib-prefix    don't search for libraries in includedir and libdir],
+  AC_ARG_WITH([lib-prefix],
+[[  --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+  --without-lib-prefix    don't search for libraries in includedir and libdir]],
 [
     if test "X$withval" = "Xno"; then
       use_additional=no
@@ -154,71 +147,177 @@ AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
 ])
 
 dnl AC_LIB_PREPARE_MULTILIB creates
-dnl - a variable acl_libdirstem, containing the basename of the libdir, either
-dnl   "lib" or "lib64" or "lib/64",
-dnl - a variable acl_libdirstem2, as a secondary possible value for
-dnl   acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or
-dnl   "lib/amd64".
+dnl - a function acl_is_expected_elfclass, that tests whether standard input
+dn;   has a 32-bit or 64-bit ELF header, depending on the host CPU ABI,
+dnl - 3 variables acl_libdirstem, acl_libdirstem2, acl_libdirstem3, containing
+dnl   the basename of the libdir to try in turn, either "lib" or "lib64" or
+dnl   "lib/64" or "lib32" or "lib/sparcv9" or "lib/amd64" or similar.
 AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
 [
-  dnl There is no formal standard regarding lib and lib64.
-  dnl On glibc systems, the current practice is that on a system supporting
+  dnl There is no formal standard regarding lib, lib32, and lib64.
+  dnl On most glibc systems, the current practice is that on a system supporting
   dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
-  dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine
-  dnl the compiler's default mode by looking at the compiler's library search
-  dnl path. If at least one of its elements ends in /lib64 or points to a
-  dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI.
-  dnl Otherwise we use the default, namely "lib".
+  dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. However, on
+  dnl Arch Linux based distributions, it's the opposite: 32-bit libraries go
+  dnl under $prefix/lib32 and 64-bit libraries go under $prefix/lib.
+  dnl We determine the compiler's default mode by looking at the compiler's
+  dnl library search path. If at least one of its elements ends in /lib64 or
+  dnl points to a directory whose absolute pathname ends in /lib64, we use that
+  dnl for 64-bit ABIs. Similarly for 32-bit ABIs. Otherwise we use the default,
+  dnl namely "lib".
   dnl On Solaris systems, the current practice is that on a system supporting
   dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
   dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or
   dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib.
   AC_REQUIRE([AC_CANONICAL_HOST])
-  acl_libdirstem=lib
-  acl_libdirstem2=
-  case "$host_os" in
-    solaris*)
-      dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment
-      dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>.
-      dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link."
-      dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the
-      dnl symlink is missing, so we set acl_libdirstem2 too.
-      AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit],
-        [AC_EGREP_CPP([sixtyfour bits], [
-#ifdef _LP64
-sixtyfour bits
-#endif
-           ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no])
-        ])
-      if test $gl_cv_solaris_64bit = yes; then
-        acl_libdirstem=lib/64
-        case "$host_cpu" in
-          sparc*)        acl_libdirstem2=lib/sparcv9 ;;
-          i*86 | x86_64) acl_libdirstem2=lib/amd64 ;;
-        esac
-      fi
-      ;;
-    *)
-      searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
-      if test -n "$searchpath"; then
-        acl_save_IFS="${IFS=   }"; IFS=":"
-        for searchdir in $searchpath; do
-          if test -d "$searchdir"; then
-            case "$searchdir" in
-              */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
-              */../ | */.. )
-                # Better ignore directories of this form. They are misleading.
-                ;;
-              *) searchdir=`cd "$searchdir" && pwd`
-                 case "$searchdir" in
-                   */lib64 ) acl_libdirstem=lib64 ;;
-                 esac ;;
-            esac
-          fi
-        done
-        IFS="$acl_save_IFS"
-      fi
-      ;;
-  esac
-  test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
+  AC_REQUIRE([gl_HOST_CPU_C_ABI_32BIT])
+
+  AC_CACHE_CHECK([for ELF binary format], [gl_cv_elf],
+    [AC_EGREP_CPP([Extensible Linking Format],
+       [#if defined __ELF__ || (defined __linux__ && defined __EDG__)
+        Extensible Linking Format
+        #endif
+       ],
+       [gl_cv_elf=yes],
+       [gl_cv_elf=no])
+    ])
+  if test $gl_cv_elf = yes; then
+    # Extract the ELF class of a file (5th byte) in decimal.
+    # Cf. https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
+    if od -A x < /dev/null >/dev/null 2>/dev/null; then
+      # Use POSIX od.
+      func_elfclass ()
+      {
+        od -A n -t d1 -j 4 -N 1
+      }
+    else
+      # Use BSD hexdump.
+      func_elfclass ()
+      {
+        dd bs=1 count=1 skip=4 2>/dev/null | hexdump -e '1/1 "%3d "'
+        echo
+      }
+    fi
+    # Use 'expr', not 'test', to compare the values of func_elfclass, because on
+    # Solaris 11 OpenIndiana and Solaris 11 OmniOS, the result is 001 or 002,
+    # not 1 or 2.
+changequote(,)dnl
+    case $HOST_CPU_C_ABI_32BIT in
+      yes)
+        # 32-bit ABI.
+        acl_is_expected_elfclass ()
+        {
+          expr "`func_elfclass | sed -e 's/[   ]//g'`" = 1 > /dev/null
+        }
+        ;;
+      no)
+        # 64-bit ABI.
+        acl_is_expected_elfclass ()
+        {
+          expr "`func_elfclass | sed -e 's/[   ]//g'`" = 2 > /dev/null
+        }
+        ;;
+      *)
+        # Unknown.
+        acl_is_expected_elfclass ()
+        {
+          :
+        }
+        ;;
+    esac
+changequote([,])dnl
+  else
+    acl_is_expected_elfclass ()
+    {
+      :
+    }
+  fi
+
+  dnl Allow the user to override the result by setting acl_cv_libdirstems.
+  AC_CACHE_CHECK([for the common suffixes of directories in the library search path],
+    [acl_cv_libdirstems],
+    [dnl Try 'lib' first, because that's the default for libdir in GNU, see
+     dnl <https://www.gnu.org/prep/standards/html_node/Directory-Variables.html>.
+     acl_libdirstem=lib
+     acl_libdirstem2=
+     acl_libdirstem3=
+     case "$host_os" in
+       solaris*)
+         dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment
+         dnl <https://docs.oracle.com/cd/E19253-01/816-5138/dev-env/index.html>.
+         dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link."
+         dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the
+         dnl symlink is missing, so we set acl_libdirstem2 too.
+         if test $HOST_CPU_C_ABI_32BIT = no; then
+           acl_libdirstem2=lib/64
+           case "$host_cpu" in
+             sparc*)        acl_libdirstem3=lib/sparcv9 ;;
+             i*86 | x86_64) acl_libdirstem3=lib/amd64 ;;
+           esac
+         fi
+         ;;
+       *)
+         dnl If $CC generates code for a 32-bit ABI, the libraries are
+         dnl surely under $prefix/lib or $prefix/lib32, not $prefix/lib64.
+         dnl Similarly, if $CC generates code for a 64-bit ABI, the libraries
+         dnl are surely under $prefix/lib or $prefix/lib64, not $prefix/lib32.
+         dnl Find the compiler's search path. However, non-system compilers
+         dnl sometimes have odd library search paths. But we can't simply invoke
+         dnl '/usr/bin/gcc -print-search-dirs' because that would not take into
+         dnl account the -m32/-m31 or -m64 options from the $CC or $CFLAGS.
+         searchpath=`(LC_ALL=C $CC $CPPFLAGS $CFLAGS -print-search-dirs) 2>/dev/null \
+                     | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
+         if test $HOST_CPU_C_ABI_32BIT != no; then
+           # 32-bit or unknown ABI.
+           if test -d /usr/lib32; then
+             acl_libdirstem2=lib32
+           fi
+         fi
+         if test $HOST_CPU_C_ABI_32BIT != yes; then
+           # 64-bit or unknown ABI.
+           if test -d /usr/lib64; then
+             acl_libdirstem3=lib64
+           fi
+         fi
+         if test -n "$searchpath"; then
+           acl_save_IFS="${IFS=        }"; IFS=":"
+           for searchdir in $searchpath; do
+             if test -d "$searchdir"; then
+               case "$searchdir" in
+                 */lib32/ | */lib32 ) acl_libdirstem2=lib32 ;;
+                 */lib64/ | */lib64 ) acl_libdirstem3=lib64 ;;
+                 */../ | */.. )
+                   # Better ignore directories of this form. They are misleading.
+                   ;;
+                 *) searchdir=`cd "$searchdir" && pwd`
+                    case "$searchdir" in
+                      */lib32 ) acl_libdirstem2=lib32 ;;
+                      */lib64 ) acl_libdirstem3=lib64 ;;
+                    esac ;;
+               esac
+             fi
+           done
+           IFS="$acl_save_IFS"
+           if test $HOST_CPU_C_ABI_32BIT = yes; then
+             # 32-bit ABI.
+             acl_libdirstem3=
+           fi
+           if test $HOST_CPU_C_ABI_32BIT = no; then
+             # 64-bit ABI.
+             acl_libdirstem2=
+           fi
+         fi
+         ;;
+     esac
+     test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
+     test -n "$acl_libdirstem3" || acl_libdirstem3="$acl_libdirstem"
+     acl_cv_libdirstems="$acl_libdirstem,$acl_libdirstem2,$acl_libdirstem3"
+    ])
+  dnl Decompose acl_cv_libdirstems into acl_libdirstem, acl_libdirstem2, and
+  dnl acl_libdirstem3.
+changequote(,)dnl
+  acl_libdirstem=`echo "$acl_cv_libdirstems" | sed -e 's/,.*//'`
+  acl_libdirstem2=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,//' -e 's/,.*//'`
+  acl_libdirstem3=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,[^,]*,//' -e 's/,.*//'`
+changequote([,])dnl
 ])
diff --git a/scripts/fixupind.py b/scripts/fixupind.py
deleted file mode 100755 (executable)
index ac2c4b9..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python3
-# encoding: utf-8
-# TeX Live 2012 seems to dislike files produces by doxygen (1.8.x.y)
-# In particular, makeindex(1) program creates invalid index entries like
-# \hyperpage{NNN_}
-# (note the trailing underscore in the page number). This breaks automatic
-# builds and is very annoying. Hence this script. It replaces (broken)
-# \hyperpage{NNN_} with \hyperpage{NNN}.
-# Note: this is an ugly work around, a proper fix is welcome.
-import sys, os, re
-
-def fixupind(fname):
-       """ Fix \\hyperpage{NNN_} entries in the ind file @var{fname} """
-       tmpout = fname + '.tmp' 
-       inp = open(fname)
-       out = open(tmpout, 'wt')
-       rx = re.compile('(hyperpage)[{]([0-9]+)[_][}]')
-       for line in inp:
-               out.write(re.sub(rx, '\\1{\\2}', line))
-       out.flush()
-       out.close()
-       inp.close()
-       os.rename(tmpout, fname)
-
-if __name__ == '__main__':
-       if len(sys.argv) <= 1:
-               sys.exit(1)
-       fixupind(sys.argv[1])
-       sys.exit(0)
-
index 734d748a02dc6af8dec3e3a8ae4d6de6ec096a6e..bc0d4f85785ccf89538fdb1a8b2eeb90af080b84 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+
 """
 Yet Another Python Templating Utility, Version 1.2, by Alex Martelli.
 Distributed under PSF license (http://docs.python.org/license.html).
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644 (file)
index 0000000..9e5b306
--- /dev/null
@@ -0,0 +1,3 @@
+viewgar
+viewgar.1
+ginac-excompiler
index 6feeb2d9c3c5296c4efd27967bd32d827f8c31dc..0c787ce65bdef88522ef660edf55ea57dc0b5b84 100644 (file)
@@ -1,9 +1,7 @@
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../ginac)
-add_definitions(-DIN_GINAC)
 
 add_executable(viewgar viewgar.cpp)
-target_link_libraries(viewgar ginac ${LIBDL_LIBRARIES})
-install(TARGETS viewgar RUNTIME DESTINATION "${BIN_INSTALL_DIR}")
+target_link_libraries(viewgar ginac::ginac)
+install(TARGETS viewgar RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
 
 if (CMAKE_COMPILER_IS_GNUCC)
        set (CC gcc)
@@ -12,5 +10,5 @@ if (CMAKE_COMPILER_IS_GNUCC)
           "${CMAKE_CURRENT_BINARY_DIR}/ginac-excompiler"
        )
 
-       install(PROGRAMS ginac-excompiler DESTINATION "${LIBEXECDIR}")
+       install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/ginac-excompiler DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}")
 endif (CMAKE_COMPILER_IS_GNUCC)
index d369206643154cfaf765191c2ff438250c3a212a..38ead99b1f422d022d8263de7b6ad33baeff1026 100644 (file)
@@ -17,20 +17,12 @@ option it will output a raw dump of the archive contents).
 print raw dump of archive instead of formatted expressions
 .SH AUTHOR
 .TP
-The GiNaC Group:
-.br
-Christian Bauer <Christian.Bauer@uni-mainz.de>
-.br
-Alexander Frink <Alexander.Frink@uni-mainz.de>
-.br
-Richard Kreckel <Richard.Kreckel@uni-mainz.de>
-.br
-Jens Vollinga <vollinga@thep.physik.uni-mainz.de>
+The GiNaC maintainers <https://www.ginac.de/>.
 .SH SEE ALSO
 GiNaC Tutorial \- An open framework for symbolic computation within the
 C++ programming language
 .SH COPYRIGHT
-Copyright \(co 1999-2019 Johannes Gutenberg Universit\(:at Mainz, Germany
+Copyright \(co 1999-2024 Johannes Gutenberg Universit\(:at Mainz, Germany
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index e16ff0f056be04befdd75c1f1b0534f67017ed55..c369591788f92fe368a21284d95fa11524effd91 100644 (file)
@@ -3,7 +3,7 @@
  *  GiNaC archive file viewer. */
 
 /*
- *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by