From: Richard Kreckel Date: Fri, 5 Apr 2024 16:34:48 +0000 (+0200) Subject: [BUGFIX] Fix crash in parser. X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=commitdiff_plain;h=HEAD;hp=bb2866ed001b2dd297fa83573ffc10dd95a12c97 [BUGFIX] Fix crash in parser. Relying on aligned functions is non-portable. Reported by Diego Conti . --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..45ae18bb --- /dev/null +++ b/.gitignore @@ -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 0e7f3092..f853d305 100644 --- 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 . - Christian Bauer - Alexander Frink - Richard Kreckel -The following people have contributed code to GiNaC: +Contributors +------------ + +The following people have contributed to GiNaC: Roberto Bagnara + Christian Bauer Chris Dams + Matthias Dellweg Do Hoang Son + Oleg Finkelshteyn + Alexander Frink Vladimir V. Kisil + Richard B. Kreckel Vitaly Magerya Markus Nullmeier + Bernard Parisse Pearu Peterson Benedikt Plümper + Jan Rheinländer Ben Sapp - Alexei Sheplyakov + Alexey Sheplyakov + Ralf Stephan Jens Vollinga + Moritz Walden Stefan Weinzierl + Oliver Welzel + Ladislav Zejda -(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 . +(Please report to mailing-list if you think you've been forgotten.) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index cdb18f09..aab81f25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index b04b3501..00000000 --- a/CVSROOT/checkoutlist +++ /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: -# -# [] -# -# comment lines begin with '#' diff --git a/CVSROOT/commitinfo b/CVSROOT/commitinfo deleted file mode 100644 index b19e7b7a..00000000 --- a/CVSROOT/commitinfo +++ /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 index 51b03f66..00000000 --- a/CVSROOT/config +++ /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 index 0accaf1b..00000000 --- a/CVSROOT/cvswrappers +++ /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 index d78886c1..00000000 --- a/CVSROOT/editinfo +++ /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 index 5a59f0a5..00000000 --- a/CVSROOT/loginfo +++ /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 index cb9e9efc..00000000 --- a/CVSROOT/modules +++ /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 index 34f0bc28..00000000 --- a/CVSROOT/notify +++ /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 index 49e59f4d..00000000 --- a/CVSROOT/rcsinfo +++ /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 index 274a46dd..00000000 --- a/CVSROOT/taginfo +++ /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 index 86f747ce..00000000 --- a/CVSROOT/verifymsg +++ /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. diff --git a/ChangeLog b/ChangeLog index b57ef5ba..7008bb49 100644 --- 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 diff --git a/GiNaC.spec.in b/GiNaC.spec.in index 4c8ebca1..1ddf85f3 100644 --- a/GiNaC.spec.in +++ b/GiNaC.spec.in @@ -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 d506b79a..07e7cf42 100644 --- 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 . +It is available from . 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 . 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: - + Finally, run diff --git a/INSTALL.CMake b/INSTALL.CMake index d4dedb5a..c36c18fc 100644 --- a/INSTALL.CMake +++ b/INSTALL.CMake @@ -2,7 +2,7 @@ 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 3 5. (optional) pkg-config utility (http://pkg-config.freedesktop.org) @@ -11,8 +11,8 @@ PREREQUISITES 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 ============ diff --git a/Makefile.am b/Makefile.am index b651383c..8d66956d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 cccbdc8b..828b0130 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,60 @@ 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(). diff --git a/README b/README index 90e549c3..e828a0eb 100644 --- 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 diff --git a/acinclude.m4 b/acinclude.m4 index 53b45e5a..35cd3862 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -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 - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - ]])], [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 ], ac_cv_have_rusage, - [AC_TRY_COMPILE([#include - #include ], - [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 + #include ]], + [[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 index 00000000..6da20c83 --- /dev/null +++ b/check/.gitignore @@ -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 diff --git a/check/CMakeLists.txt b/check/CMakeLists.txt index c229a818..db949115 100644 --- a/check/CMakeLists.txt +++ b/check/CMakeLists.txt @@ -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 @@ -30,13 +26,19 @@ set(ginac_tests exam_archive exam_structure 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 @@ -70,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 $) 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 index 00000000..4f87c572 --- /dev/null +++ b/check/FILES @@ -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 diff --git a/check/Makefile.am b/check/Makefile.am index e8adab07..0c119d52 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -1,41 +1,43 @@ ## 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_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 \ @@ -62,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 @@ -108,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 @@ -147,15 +146,36 @@ exam_structure_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 @@ -255,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 diff --git a/check/exam_cra.cpp b/check/check_cra.cpp similarity index 98% rename from check/exam_cra.cpp rename to check/check_cra.cpp index c875b4f8..e3f86a19 100644 --- a/check/exam_cra.cpp +++ b/check/check_cra.cpp @@ -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 diff --git a/check/check_inifcns.cpp b/check/check_inifcns.cpp index b775d577..6c212dc4 100644 --- a/check/check_inifcns.cpp +++ b/check/check_inifcns.cpp @@ -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/check_lsolve.cpp b/check/check_lsolve.cpp index d09b6e9d..8496b45c 100644 --- a/check/check_lsolve.cpp +++ b/check/check_lsolve.cpp @@ -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 diff --git a/check/check_matrices.cpp b/check/check_matrices.cpp index a714523b..f0e38352 100644 --- a/check/check_matrices.cpp +++ b/check/check_matrices.cpp @@ -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 index 34652f8d..00000000 --- a/check/check_mul_info.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "ginac.h" -#include -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; -} diff --git a/check/check_numeric.cpp b/check/check_numeric.cpp index 2904a969..a2b08a9c 100644 --- a/check/check_numeric.cpp +++ b/check/check_numeric.cpp @@ -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 diff --git a/check/error_report.h b/check/error_report.h index 47a30d28..a5db7425 100644 --- a/check/error_report.h +++ b/check/error_report.h @@ -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 diff --git a/check/exam_archive.cpp b/check/exam_archive.cpp index 198df414..fcc3b7ad 100644 --- a/check/exam_archive.cpp +++ b/check/exam_archive.cpp @@ -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 using namespace std; +#include + + 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 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; } diff --git a/check/bugme_chinrem_gcd.cpp b/check/exam_chinrem_gcd.cpp similarity index 96% rename from check/bugme_chinrem_gcd.cpp rename to check/exam_chinrem_gcd.cpp index b3161e8a..b020a71e 100644 --- a/check/bugme_chinrem_gcd.cpp +++ b/check/exam_chinrem_gcd.cpp @@ -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(); diff --git a/check/exam_clifford.cpp b/check/exam_clifford.cpp index b067438b..3c90a327 100644 --- a/check/exam_clifford.cpp +++ b/check/exam_clifford.cpp @@ -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 index 00000000..65cad598 --- /dev/null +++ b/check/exam_collect.cpp @@ -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 +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 index 00000000..520e0d84 --- /dev/null +++ b/check/exam_collect_common_factors.cpp @@ -0,0 +1,59 @@ +#include +#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; +} diff --git a/check/exam_color.cpp b/check/exam_color.cpp index e3285894..590cf2db 100644 --- a/check/exam_color.cpp +++ b/check/exam_color.cpp @@ -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 diff --git a/check/exam_differentiation.cpp b/check/exam_differentiation.cpp index 1cc41b76..39baeafc 100644 --- a/check/exam_differentiation.cpp +++ b/check/exam_differentiation.cpp @@ -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 diff --git a/check/exam_factor.cpp b/check/exam_factor.cpp index ce4d7027..cf1dd06c 100644 --- a/check/exam_factor.cpp +++ b/check/exam_factor.cpp @@ -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 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(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 index 00000000..b5b5d0d7 --- /dev/null +++ b/check/exam_function_exvector.cpp @@ -0,0 +1,116 @@ +#ifdef IN_GINAC +#include "ginac.h" +#else +#include "ginac/ginac.h" +#endif + +#include +#include + +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(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(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/heur_gcd_bug.cpp b/check/exam_heur_gcd.cpp similarity index 90% rename from check/heur_gcd_bug.cpp rename to check/exam_heur_gcd.cpp index 40db72cc..064a4339 100644 --- a/check/heur_gcd_bug.cpp +++ b/check/exam_heur_gcd.cpp @@ -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); diff --git a/check/exam_indexed.cpp b/check/exam_indexed.cpp index 34dde3b2..60209510 100644 --- a/check/exam_indexed.cpp +++ b/check/exam_indexed.cpp @@ -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 diff --git a/check/exam_inifcns.cpp b/check/exam_inifcns.cpp index 667d0842..a2c6a933 100644 --- a/check/exam_inifcns.cpp +++ b/check/exam_inifcns.cpp @@ -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 index 00000000..7e79d96a --- /dev/null +++ b/check/exam_inifcns_elliptic.cpp @@ -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 +#include +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(eta).get_numerical_value(qbar_prime,N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_2,N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_2,N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_4,N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_6,3*N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_12,6*N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_2,N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_6,2*N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_12,4*N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_3,N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(eta).get_numerical_value(qbar_prime_6,2*N_trunc); + res2 = pow(c*tau+d,k)*ex_to(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(); +} diff --git a/check/exam_inifcns_nstdsums.cpp b/check/exam_inifcns_nstdsums.cpp index 86c6416b..5b1baf6b 100644 --- a/check/exam_inifcns_nstdsums.cpp +++ b/check/exam_inifcns_nstdsums.cpp @@ -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; diff --git a/check/exam_inifcns_nstdsums.h b/check/exam_inifcns_nstdsums.h index 272b15b4..60e2fe34 100644 --- a/check/exam_inifcns_nstdsums.h +++ b/check/exam_inifcns_nstdsums.h @@ -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 diff --git a/check/exam_lsolve.cpp b/check/exam_lsolve.cpp index 422f7be5..6da7a7b9 100644 --- a/check/exam_lsolve.cpp +++ b/check/exam_lsolve.cpp @@ -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 diff --git a/check/match_bug.cpp b/check/exam_match.cpp similarity index 93% rename from check/match_bug.cpp rename to check/exam_match.cpp index c0181baa..f71ec4d4 100644 --- a/check/match_bug.cpp +++ b/check/exam_match.cpp @@ -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); diff --git a/check/exam_matrices.cpp b/check/exam_matrices.cpp index b163386f..1d5b0817 100644 --- a/check/exam_matrices.cpp +++ b/check/exam_matrices.cpp @@ -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) { diff --git a/check/exam_misc.cpp b/check/exam_misc.cpp index 13152f27..31e0e9e2 100644 --- a/check/exam_misc.cpp +++ b/check/exam_misc.cpp @@ -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; } diff --git a/check/exam_mod_gcd.cpp b/check/exam_mod_gcd.cpp index c551c673..5b0675c9 100644 --- a/check/exam_mod_gcd.cpp +++ b/check/exam_mod_gcd.cpp @@ -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 diff --git a/check/exam_normalization.cpp b/check/exam_normalization.cpp index ade01a68..ded231f3 100644 --- a/check/exam_normalization.cpp +++ b/check/exam_normalization.cpp @@ -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; } diff --git a/check/exam_numeric.cpp b/check/exam_numeric.cpp index ad7da61c..ebea234d 100644 --- a/check/exam_numeric.cpp +++ b/check/exam_numeric.cpp @@ -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 diff --git a/check/exam_paranoia.cpp b/check/exam_paranoia.cpp index b5f12608..d8a6027d 100644 --- a/check/exam_paranoia.cpp +++ b/check/exam_paranoia.cpp @@ -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 index 00000000..2c65cd54 --- /dev/null +++ b/check/exam_parser.cpp @@ -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 +#include +#include +#include + +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 index 00000000..0d61c6ef --- /dev/null +++ b/check/exam_pgcd.cpp @@ -0,0 +1,68 @@ +/** @file exam_pgcd.cpp + * + * Exam GCD over prime fields computations. + */ +#include +#include +#include +#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(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; +} diff --git a/check/exam_polygcd.cpp b/check/exam_polygcd.cpp index aac25c85..ba2570da 100644 --- a/check/exam_polygcd.cpp +++ b/check/exam_polygcd.cpp @@ -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 diff --git a/check/exam_powerlaws.cpp b/check/exam_powerlaws.cpp index fb7328f5..b6b10552 100644 --- a/check/exam_powerlaws.cpp +++ b/check/exam_powerlaws.cpp @@ -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 diff --git a/check/exam_pseries.cpp b/check/exam_pseries.cpp index e59026c4..c2669c42 100644 --- a/check/exam_pseries.cpp +++ b/check/exam_pseries.cpp @@ -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; } diff --git a/check/exam_real_imag.cpp b/check/exam_real_imag.cpp index dc24f0a2..7c0b4415 100644 --- a/check/exam_real_imag.cpp +++ b/check/exam_real_imag.cpp @@ -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 index 00000000..ec9a2d78 --- /dev/null +++ b/check/exam_relational.cpp @@ -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 +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 index 00000000..014d703f --- /dev/null +++ b/check/exam_sqrfree.cpp @@ -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 +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> 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(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; +} diff --git a/check/exam_structure.cpp b/check/exam_structure.cpp index 5aa16374..b9a403a9 100644 --- a/check/exam_structure.cpp +++ b/check/exam_structure.cpp @@ -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 index 80a7ce4c..00000000 --- a/check/factor_univariate_bug.cpp +++ /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 -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; -} diff --git a/check/genex.cpp b/check/genex.cpp index 981e193c..84b7fc0e 100644 --- a/check/genex.cpp +++ b/check/genex.cpp @@ -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 index 0d2b1d6e..00000000 --- a/check/mul_eval_memleak.cpp +++ /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 - * Date: Wed Jul 11 14:34:42 2007 +0400 - * (it was commited into the official branch as - * commit a602d34c225dceb3e53742a7b3e19a4b5e280485 - * Author: Jens Vollinga - * 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 -using namespace GiNaC; - -#include -#include -#include -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 -#include -#include - -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 index a7d410c4..00000000 --- a/check/numeric_archive.cpp +++ /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 -#include -#include -#include -#include -#include -#include -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 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 index 38210493..00000000 --- a/check/parser_bugs.cpp +++ /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 -#include -#include -#include - -// - 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 index ffe095df..00000000 --- a/check/parser_memleak.cpp +++ /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 -using namespace GiNaC; - -#include -#include -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 index 0ad5a70d..00000000 --- a/check/pgcd_infinite_loop.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#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(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 index 1d4c287b..00000000 --- a/check/pgcd_relatively_prime_bug.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/** @file pgcd_relatively_prime_bug.cpp - * - * A program exposing historical bug in the pgcd() function. - */ -#include -#include -#include -#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; -} - diff --git a/check/randomize_serials.cpp b/check/randomize_serials.cpp index ab34ba00..98194494 100644 --- a/check/randomize_serials.cpp +++ b/check/randomize_serials.cpp @@ -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 diff --git a/check/test_runner.h b/check/test_runner.h index 4a306350..e3c7315a 100644 --- a/check/test_runner.h +++ b/check/test_runner.h @@ -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 diff --git a/check/time_antipode.cpp b/check/time_antipode.cpp index 24da0b75..b5109ce8 100644 --- a/check/time_antipode.cpp +++ b/check/time_antipode.cpp @@ -12,11 +12,11 @@ * This program is based on work by * Isabella Bierenbaum and * Dirk Kreimer . - * For details, please see . + * For details, please see . */ /* - * 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, 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*) diff --git a/configure.ac b/configure.ac index 3c2311b6..96c89358 100644 --- a/configure.ac +++ b/configure.ac @@ -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"], diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index e1416d31..e38e2a19 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -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 index 00000000..b9e3b6e0 --- /dev/null +++ b/doc/examples/.gitignore @@ -0,0 +1,3 @@ +*.html +*.info +*.txt diff --git a/doc/examples/CMakeLists.txt b/doc/examples/CMakeLists.txt index 851c61ce..ea5f64d7 100644 --- a/doc/examples/CMakeLists.txt +++ b/doc/examples/CMakeLists.txt @@ -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) diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index 472a2a16..9c66c731 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -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 diff --git a/doc/examples/archive1.cpp b/doc/examples/archive1.cpp index c20db620..611a15dc 100644 --- a/doc/examples/archive1.cpp +++ b/doc/examples/archive1.cpp @@ -3,8 +3,13 @@ */ #include -using namespace std; + +#ifdef IN_GINAC +#include "ginac.h" +#else #include +#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"); diff --git a/doc/examples/compile1.cpp b/doc/examples/compile1.cpp index c63b9ca0..8734cdec 100644 --- a/doc/examples/compile1.cpp +++ b/doc/examples/compile1.cpp @@ -1,7 +1,11 @@ #include #include -using namespace std; +#ifdef IN_GINAC +#include "ginac.h" +#else #include +#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) { diff --git a/doc/examples/compile2.cpp b/doc/examples/compile2.cpp index faff99cc..0854e722 100644 --- a/doc/examples/compile2.cpp +++ b/doc/examples/compile2.cpp @@ -1,10 +1,15 @@ #include -using namespace std; +#ifdef IN_GINAC +#include "ginac.h" +#else #include -using namespace GiNaC; +#endif // Yes, we are using CUBA (should be installed on the system!) #include +using namespace std; +using namespace GiNaC; + /* * Demonstrates the use of compile_ex with the CUBA library. * diff --git a/doc/examples/compile3.cpp b/doc/examples/compile3.cpp index 993c3b9f..c0e5209f 100644 --- a/doc/examples/compile3.cpp +++ b/doc/examples/compile3.cpp @@ -1,7 +1,11 @@ #include #include -using namespace std; +#ifdef IN_GINAC +#include "ginac.h" +#else #include +#endif +using namespace std; using namespace GiNaC; /* diff --git a/doc/examples/derivative.cpp b/doc/examples/derivative.cpp index c1a09b99..3b845c05 100644 --- a/doc/examples/derivative.cpp +++ b/doc/examples/derivative.cpp @@ -5,7 +5,11 @@ #include #include #include +#ifdef IN_GINAC +#include "ginac.h" +#else #include +#endif using namespace std; using namespace GiNaC; diff --git a/doc/examples/lanczos.cpp b/doc/examples/lanczos.cpp index 627bb3f8..4a09525a 100644 --- a/doc/examples/lanczos.cpp +++ b/doc/examples/lanczos.cpp @@ -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 #include #include // for size_t #include diff --git a/doc/examples/mystring.cpp b/doc/examples/mystring.cpp index bcbf96a8..655fe825 100644 --- a/doc/examples/mystring.cpp +++ b/doc/examples/mystring.cpp @@ -4,9 +4,12 @@ #include #include #include -using namespace std; - +#ifdef IN_GINAC +#include "ginac.h" +#else #include +#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 This page is part of the GiNaC +href="https://www.ginac.de/">GiNaC developer's reference. It was generated automatically by doxygen. For +href="https://www.doxygen.nl/">doxygen. For an introduction, see the tutorial. diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am index 445eeb72..5ad8a000 100644 --- a/doc/reference/Makefile.am +++ b/doc/reference/Makefile.am @@ -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 index 00000000..5556e563 --- /dev/null +++ b/doc/tutorial/.gitignore @@ -0,0 +1,3 @@ +*.info +stamp-vti +version.texi diff --git a/doc/tutorial/ginac.texi b/doc/tutorial/ginac.texi index b348b89b..52c5828e 100644 --- a/doc/tutorial/ginac.texi +++ b/doc/tutorial/ginac.texi @@ -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. @@ -1192,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 @@ -1864,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(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 @@ -3222,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} @@ -3233,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} @@ -3306,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 @@ -3824,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. @@ -4852,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 @@ -5358,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 @@ -5679,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; @@ -5871,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()} @@ -5886,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()} @@ -5966,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 @@ -5980,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 @@ -6149,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 @@ -6694,8 +6815,8 @@ expression a unique name: @example #include -using namespace std; #include +using namespace std; using namespace GiNaC; int main() @@ -7611,9 +7732,8 @@ product in a C++ @code{struct}: @example #include -using namespace std; - #include +using namespace std; using namespace GiNaC; struct sprod_s @{ @@ -8005,9 +8125,8 @@ as follows: #include #include #include -using namespace std; - #include +using namespace std; using namespace GiNaC; @end example @@ -8586,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 @@ -8687,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 diff --git a/ginac.pc.cmake b/ginac.pc.cmake index 4b168bea..18543ecf 100644 --- a/ginac.pc.cmake +++ b/ginac.pc.cmake @@ -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 diff --git a/ginac.pc.in b/ginac.pc.in index dce536b1..cacda9b5 100644 --- a/ginac.pc.in +++ b/ginac.pc.in @@ -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 index 00000000..f4c5d0da --- /dev/null +++ b/ginac/.gitignore @@ -0,0 +1,4 @@ +.libs/ +function.h +function.cpp +.Tpo diff --git a/ginac/CMakeLists.txt b/ginac/CMakeLists.txt index 27f4db8d..5b0937c4 100644 --- a/ginac/CMakeLists.txt +++ b/ginac/CMakeLists.txt @@ -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 $ + PRIVATE -DLIBEXECDIR="${LIBEXECDIR}/" HAVE_CONFIG_H +) +target_link_libraries(ginac PUBLIC cln::cln ${LIBDL_LIBRARIES}) +target_include_directories(ginac PUBLIC + $ + $ + $ + $ +) + +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) diff --git a/ginac/Makefile.am b/ginac/Makefile.am index cb76517a..0dc82c15 100644 --- a/ginac/Makefile.am +++ b/ginac/Makefile.am @@ -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 \ diff --git a/ginac/add.cpp b/ginac/add.cpp index 6c83e2a7..b9f47938 100644 --- a/ginac/add.cpp +++ b/ginac/add.cpp @@ -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 diff --git a/ginac/add.h b/ginac/add.h index 081af04a..f7c64e08 100644 --- a/ginac/add.h +++ b/ginac/add.h @@ -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; diff --git a/ginac/archive.cpp b/ginac/archive.cpp index 0eed3d54..82d2b68b 100644 --- a/ginac/archive.cpp +++ b/ginac/archive.cpp @@ -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 @@ -612,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). */ diff --git a/ginac/archive.h b/ginac/archive.h index c3314f13..8b7a3e4a 100644 --- a/ginac/archive.h +++ b/ginac/archive.h @@ -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 diff --git a/ginac/assertion.h b/ginac/assertion.h index 6e2942c2..7bac1769 100644 --- a/ginac/assertion.h +++ b/ginac/assertion.h @@ -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 diff --git a/ginac/basic.cpp b/ginac/basic.cpp index 1d5f695a..b5f97cda 100644 --- a/ginac/basic.cpp +++ b/ginac/basic.cpp @@ -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 diff --git a/ginac/basic.h b/ginac/basic.h index 1a471b32..850bc91d 100644 --- a/ginac/basic.h +++ b/ginac/basic.h @@ -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; diff --git a/ginac/class_info.h b/ginac/class_info.h index 3f3413b0..1db15620 100644 --- a/ginac/class_info.h +++ b/ginac/class_info.h @@ -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 diff --git a/ginac/clifford.cpp b/ginac/clifford.cpp index 860cce46..2cf0facf 100644 --- a/ginac/clifford.cpp +++ b/ginac/clifford.cpp @@ -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(e1.op(i)) && is_a(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(e1.op(i)) && ex_to(e1.op(i)).get_representation_label() == rl diff --git a/ginac/clifford.h b/ginac/clifford.h index c076d615..0b78c497 100644 --- a/ginac/clifford.h +++ b/ginac/clifford.h @@ -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 diff --git a/ginac/color.cpp b/ginac/color.cpp index f8cbca07..accdccdb 100644 --- a/ginac/color.cpp +++ b/ginac/color.cpp @@ -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 diff --git a/ginac/color.h b/ginac/color.h index 4dbfc3d4..828b8c0b 100644 --- a/ginac/color.h +++ b/ginac/color.h @@ -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 diff --git a/ginac/compiler.h b/ginac/compiler.h index 08099f57..e9682794 100644 --- a/ginac/compiler.h +++ b/ginac/compiler.h @@ -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 diff --git a/ginac/constant.cpp b/ginac/constant.cpp index 85af0c14..7bdd244b 100644 --- a/ginac/constant.cpp +++ b/ginac/constant.cpp @@ -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 diff --git a/ginac/constant.h b/ginac/constant.h index 7e8916da..55ff5e5d 100644 --- a/ginac/constant.h +++ b/ginac/constant.h @@ -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 diff --git a/ginac/container.h b/ginac/container.h index 4360bcc0..90829710 100644 --- a/ginac/container.h +++ b/ginac/container.h @@ -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::reserve(std::vector & v, size_t n) { v.reserve(n); } -/** Helper template to allow initialization of containers via an overloaded - * comma operator (idea stolen from Blitz++). */ -template -class container_init { -public: - container_init(STLT & s) : stlt(s) {} - - container_init operator,(const T & x) - { - stlt.push_back(x); - return container_init(stlt); - } - - // The following specializations produce much tighter code than the - // general case above - - container_init operator,(int x) - { - stlt.push_back(x); - return container_init(stlt); - } - - container_init operator,(unsigned int x) - { - stlt.push_back(x); - return container_init(stlt); - } - - container_init operator,(long x) - { - stlt.push_back(x); - return container_init(stlt); - } - - container_init operator,(unsigned long x) - { - stlt.push_back(x); - return container_init(stlt); - } - - container_init operator,(double x) - { - stlt.push_back(x); - return container_init(stlt); - } - - container_init operator,(const symbol & x) - { - stlt.push_back(T(x)); - return container_init(stlt); - } - -private: - container_init(); - STLT & stlt; -}; - /** Wrapper template for making GiNaC classes out of STL containers. */ template