...which is a C++20 feature. This fixes MSVC build.
Reported by Igor Machado <igor.machado@gmail.com>.
--- /dev/null
+.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
-GiNaC was originally written by:
+Contacting the developers
+-------------------------
+
+If you have found a bug, have a patch or a question, or would like to
+make a suggestion please send email to one of our public mailing lists
+instead of to the authors. This avoids both potential duplication of
+work and delays caused by possible vacations. Mailing list subscription
+is explained at <https://www.ginac.de/Lists.html>.
- Christian Bauer <Christian.Bauer@uni-mainz.de>
- Alexander Frink <Alexander.Frink@uni-mainz.de>
- Richard Kreckel <Richard.Kreckel@uni-mainz.de>
-The following people have contributed code to GiNaC:
+Contributors
+------------
+
+The following people have contributed to GiNaC:
Roberto Bagnara <bagnara@cs.unipr.it>
+ Christian Bauer <Christian.Bauer@uni-mainz.de>
Chris Dams <Chris.Dams@mi.infn.it>
+ Matthias Dellweg <dellweg@tp1.uni-duesseldorf.de>
Do Hoang Son <dhson@phys.hcmuns.edu.vn>
+ Oleg Finkelshteyn <olegfink@gmail.com>
+ Alexander Frink <Alexander.Frink@uni-mainz.de>
Vladimir V. Kisil <kisilv@maths.leeds.ac.uk>
+ Richard B. Kreckel <kreckel@in.terlu.de>
Vitaly Magerya <vmagerya@gmail.com>
Markus Nullmeier <markus.nullmeier@urz.uni-heidelberg.de>
+ Bernard Parisse <Bernard.Parisse@ujf-grenoble.fr>
Pearu Peterson <pearu@cens.ioc.ee>
Benedikt Plümper <pluemper@thep.physik.uni-mainz.de>
+ Jan Rheinländer <jrheinlaender@gmx.de>
Ben Sapp <bsapp@lanl.gov>
- Alexei Sheplyakov <varg@theor.jinr.ru>
+ Alexey Sheplyakov <varg@theor.jinr.ru>
+ Ralf Stephan <gtrwst9@gmail.com>
Jens Vollinga <vollinga@thep.physik.uni-mainz.de>
+ Moritz Walden <mwalde01@students.uni-mainz.de>
Stefan Weinzierl <weinzierl@uni-mainz.de>
+ Oliver Welzel <welzel@thep.physik.uni-mainz.de>
+ Ladislav Zejda <lzejda@gmail.com>
-(Please send email if you think you were forgotten.)
-
-
-Contacing the developers
-------------------------
-
-If you have found a bug, have a patch or a question, or would like to
-make a suggestion please send email to one of our public mailing lists
-instead of to the authors. This avoids both potential duplication of
-work and delays caused by possible vacations. Mailing list subscription
-is explained at <http://www.ginac.de/Lists.html>.
+(Please report to mailing-list if you think you've been forgotten.)
\ No newline at end of file
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}")
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)
# 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()
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}")
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 "
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)
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")
+++ /dev/null
-# The "checkoutlist" file is used to support additional version controlled
-# administrative files in $CVSROOT/CVSROOT, such as template files.
-#
-# The first entry on a line is a filename which will be checked out from
-# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
-# The remainder of the line is an error message to use if the file cannot
-# be checked out.
-#
-# File format:
-#
-# [<whitespace>]<filename><whitespace><error message><end-of-line>
-#
-# comment lines begin with '#'
+++ /dev/null
-# 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".
+++ /dev/null
-# 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
+++ /dev/null
-# 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'
+++ /dev/null
-# 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.
+++ /dev/null
-# 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
+++ /dev/null
-# 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.
+++ /dev/null
-# 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"
+++ /dev/null
-# 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".
+++ /dev/null
-# 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".
+++ /dev/null
-# 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.
$ 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
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}
=============
GiNaC requires the CLN library by Bruno Haible installed on your system.
-It is available from <http://www.ginac.de/CLN/>.
+It is available from <https://www.ginac.de/CLN/>.
You will also need a decent ISO C++-11 compiler. We recommend the C++
compiler from the GNU compiler collection, GCC >= 4.8. If you have a
from <http://pkg-config.freedesktop.org/>. Also, Python 3 is required.
To build the GiNaC tutorial and reference manual the doxygen utility
-(it can be downloaded from http://www.stack.nl/~dimitri/doxygen) and
-TeX are necessary.
+(it can be downloaded from https://www.doxygen.nl/) and TeX are necessary.
Known to work with:
- Linux on x86 and x86_64 using
- - GCC 4.8, 4.9, 5.1, 5.2, 5.3, and 6.1
- - Clang 3.5, 3.6, 3.7, 3.8
+ - GCC 4.8, 4.9, 5.x, 6.x, 7.x, 8.x, and 9.x
+ - Clang 3.5, 3.6, 3.7, 3.8, 6.x, 7.x, 8.x, and 9.x
Known not to work with:
- Clang 2.7 and earlier due to poor C++ support.
- GCC < 4.6.0 due to missing C++-11 support
If you install from git, you also need GNU autoconf (>=2.59), automake (>=1.8),
-libtool (>= 1.5), python3, bison (>= 2.3), flex (>= 2.5.33) to be installed.
+libtool (>= 1.5), python (version 2.7 or 3.x), bison (>= 2.3), flex (>= 2.5.33)
+to be installed.
INSTALLATION
Secondly, make sure all required software is installed. This is *really*
important step. If some package is missing, the `configure' script might
be misgenerated, see e.g. this discussion:
-<http://www.ginac.de/pipermail/ginac-list/2007-November/001263.html>
+<https://www.ginac.de/pipermail/ginac-list/2007-November/001263.html>
Finally, run
=============
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)
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
============
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)
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().
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
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
define(GINAC_GET_LTVERSION,
[GINAC_HEADER_GETVAL(GINAC_LT_$1,[ginac/version.h])])
-dnl Usage: GINAC_STD_CXX_HEADERS
-dnl Check for standard C++ headers, bail out if something is missing.
-AC_DEFUN([GINAC_STD_CXX_HEADERS], [
-AC_CACHE_CHECK([for standard C++ header files], [ginac_cv_std_cxx_headers], [
- ginac_cv_std_cxx_headers="no"
- AC_LANG_PUSH([C++])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #include <algorithm>
- #include <cstddef>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <cstdint>
- #include <ctime>
- #include <fstream>
- #include <functional>
- #include <iomanip>
- #include <ios>
- #include <iosfwd>
- #include <iostream>
- #include <iterator>
- #include <limits>
- #include <list>
- #include <map>
- #include <memory>
- #include <numeric>
- #include <ostream>
- #include <set>
- #include <sstream>
- #include <stack>
- #include <stdexcept>
- #include <string>
- #include <typeinfo>
- #include <utility>
- #include <vector>
- ]])], [ginac_cv_std_cxx_headers="yes"])
- AC_LANG_POP([C++])])
-if test "${ginac_cv_std_cxx_headers}" != "yes"; then
- AC_MSG_ERROR([Standard ISO C++ headers are missing])
-fi
-])
-
dnl Usage: GINAC_LIBREADLINE
dnl
dnl Check if GNU readline library and headers are avialable.
AC_DEFUN([GINAC_HAVE_RUSAGE],
[AC_CACHE_CHECK([whether struct rusage is declared in <sys/resource.h>],
ac_cv_have_rusage,
- [AC_TRY_COMPILE([#include <sys/times.h>
- #include <sys/resource.h>],
- [struct rusage resUsage;
- getrusage(RUSAGE_SELF, &resUsage);
- return 0;],
- [ac_cv_have_rusage=yes],
- [ac_cv_have_rusage=no])
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/times.h>
+ #include <sys/resource.h>]],
+ [[struct rusage resUsage;
+ getrusage(RUSAGE_SELF, &resUsage);
+ return 0;]])],
+ [ac_cv_have_rusage=yes],
+ [ac_cv_have_rusage=no])
])
CONFIG_RUSAGE="no"
if test "$ac_cv_have_rusage" = yes; then
--- /dev/null
+.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
-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
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
set(${thename}_sources ${thename}.cpp ${${thename}_extra_src})
endif()
add_executable(${thename} EXCLUDE_FROM_ALL ${${thename}_sources})
- target_link_libraries(${thename} ginac ${LIBDL_LIBRARIES})
+ target_link_libraries(${thename} ginac::ginac)
+ add_dependencies(test_suite ${thename})
add_dependencies(check ${thename})
- add_test(NAME ${thename} COMMAND ${thename}${CMAKE_EXECUTABLE_SUFFIX})
+ add_test(NAME ${thename} COMMAND $<TARGET_FILE:${thename}>)
endmacro()
macro(add_ginac_timing thename)
set(${thename}_extra_src timer.cpp randomize_serials.cpp)
add_ginac_test(${thename})
+ target_compile_definitions(${thename} PRIVATE HAVE_CONFIG_H)
endmacro()
set(check_matrices_extra_src genex.cpp)
set(check_lsolve_extra_src genex.cpp)
-set(exam_heur_gcd_sources heur_gcd_bug.cpp)
-set(exam_numeric_archive_sources numeric_archive.cpp)
-foreach(tst ${ginac_tests})
- add_ginac_test(${tst})
+foreach(exm ${ginac_exams})
+ add_ginac_test(${exm})
+endforeach()
+
+foreach(chk ${ginac_checks})
+ add_ginac_test(${chk})
endforeach()
foreach(tmr ${ginac_timings})
--- /dev/null
+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
## 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 \
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
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
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
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
* Test of Chinese remainder algorithm. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This 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 underlying symbolic manipulations. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* manipulations. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+++ /dev/null
-#include "ginac.h"
-#include <iostream>
-using namespace GiNaC;
-
-int main(int argc, char** argv)
-{
- symbol x("x"), y("y");
- ex e = x*y;
- if (!e.info(info_flags::indefinite)) {
- std::cerr << "eek, product of two symbols is NOT indefinite";
- return 1;
- }
- return 0;
-}
* tests on these numbers like is_integer() etc... */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Here we test GiNaC's archiving system. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <iostream>
using namespace std;
+#include <cln/cln.h>
+
+
unsigned exam_archive()
{
unsigned result = 0;
- cout << "examining archiving system" << flush;
-
symbol x("x"), y("y"), mu("mu"), dim("dim", "\\Delta");
ex e, f;
return result;
}
+/** numeric::archive used to fail if the real part of a complex number
+ * is a rational number and the imaginary part is a floating point one. */
+unsigned numeric_complex_bug()
+{
+ using namespace cln;
+ struct archive_unarchive_check
+ {
+ unsigned operator()(const cl_N& n) const
+ {
+ ex e = numeric(n);
+ archive ar;
+ ar.archive_ex(e, "test");
+ ex check = ar.unarchive_ex(lst{}, "test");
+ if (!check.is_equal(e)) {
+ clog << __FILE__ << ':' << __LINE__ << ": expected: " << e << ", got " << check << endl;
+ return 1;
+ }
+ return 0;
+ }
+ } checker;
+ unsigned result = 0;
+ const cl_I one(1);
+ const cl_R three_fp = cl_float(3.0);
+ std::vector<cl_N> numbers = {
+ complex(one, one),
+ complex(one, three_fp),
+ complex(three_fp, one),
+ complex(three_fp, three_fp)
+ };
+ for (auto & n : numbers) {
+ result += checker(n);
+ }
+ return result;
+}
+
int main(int argc, char** argv)
{
- return exam_archive();
+ unsigned result = 0;
+
+ cout << "examining archiving system" << flush;
+
+ result += exam_archive(); cout << '.' << flush;
+ result += numeric_complex_bug(); cout << '.' << flush;
+
+ return result;
}
-/** @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-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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();
* Here we test GiNaC's Clifford algebra objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- /dev/null
+/** @file exam_collect.cpp
+ *
+ */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+using namespace std;
+
+// Correctness of .collect(Z[x], x).
+static unsigned exam_collect_1()
+{
+ unsigned result = 0;
+ symbol x("x"), y("y");
+ ex a = (pow(x, 3) - 2*pow(x, 2) + 4*x) * pow(y, 2)
+ + (pow(x, 2) - x - 1) * y
+ + (x + 1);
+ ex b = pow(y, 2) * pow(x, 3)
+ + (y - 2*pow(y, 2)) * pow(x, 2)
+ + (4*pow(y, 2) - y + 1) * x
+ + (1 - y);
+
+ ex a_x = collect(a, x);
+ if (a_x != b) {
+ clog << "collect(" << a << ", " << x << ") erroneously returned "
+ << a_x << " instead of " << b << endl;
+ ++result;
+ }
+
+ ex b_y = collect(b, y);
+ if (b_y != a) {
+ clog << "collect(" << b << ", " << y << ") erroneously returned "
+ << b_y << " instead of " << a << endl;
+ ++result;
+ }
+
+ ex amb_x = collect(a - b, x);
+ if (amb_x != 0) {
+ clog << "collect(" << a - b << ", " << x << ") erroneously returned "
+ << amb_x << " instead of 0" << endl;
+ ++result;
+ }
+
+ ex amb_y = collect(a - b, y);
+ if (amb_y != 0) {
+ clog << "collect(" << a - b << ", " << y << ") erroneously returned "
+ << amb_y << " instead of 0" << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+// Consistency of .collect(Z[x,y], {x,y}) with .coeff(x).
+static unsigned exam_collect_2()
+{
+ unsigned result = 0;
+ symbol x("x"), y("y"), p("p"), q("q");
+
+ ex e1 = x + y;
+ ex e2 = 1 + p + q;
+ ex a = expand(e1 * e2);
+
+ ex a_x = a.collect(x).coeff(x, 1);
+ if (a_x != e2) {
+ clog << "collect(" << a << ", " << x << ") erroneously returned "
+ << a_x << " as coefficient of " << x << endl;
+ ++result;
+ }
+
+ ex a_p = a.collect(p).coeff(p, 1);
+ if (a_p != e1) {
+ clog << "collect(" << a << ", " << p << ") erroneously returned "
+ << a_p << " as coefficient of " << p << endl;
+ ++result;
+ }
+
+ ex a_xy = a.collect(lst{x,y});
+ ex ref = e2*x + e2*y;
+ if (a_xy != ref) {
+ clog << "collect(" << a << ", {" << x << ", " << y << "}) erroneously returned "
+ << a_xy << " instead of " << ref << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+// Consistency of .collect(Z[f(x)], f(x)) with .coeff(f(x)).
+static unsigned exam_collect_3()
+{
+ unsigned result = 0;
+ symbol x("x"), p("p"), q("q");
+
+ for (unsigned deg = 2; deg < 7; ++deg) {
+
+ ex a1 = expand(pow(p + q + x, deg));
+ a1 = a1.collect(x);
+
+ ex a2 = expand(pow(p + q + sin(x), deg));
+ a2 = a2.collect(sin(x));
+
+ for (unsigned i = 0; i < deg; ++i) {
+ ex a1_i = a1.coeff(x, i);
+ ex a2_i = a2.coeff(sin(x), i);
+ if (!expand(a1_i - a2_i).is_zero()) {
+ clog << "collect(" << a1 << ",sin(x)) inconsistent with "
+ "collect(" << a2 << ",x)" << endl;
+ ++result;
+ }
+ }
+ }
+
+ return result;
+}
+
+unsigned exam_collect()
+{
+ unsigned result = 0;
+
+ cout << "examining collect coefficients" << flush;
+
+ result += exam_collect_1(); cout << '.' << flush;
+ result += exam_collect_2(); cout << '.' << flush;
+ result += exam_collect_3(); cout << '.' << flush;
+
+ return result;
+}
+
+int main(int argc, char** argv)
+{
+ return exam_collect();
+}
--- /dev/null
+#include <iostream>
+#include "ginac.h"
+using namespace std;
+using namespace GiNaC;
+
+static unsigned exam_collect_common_factors_simple()
+{
+ unsigned result = 0;
+ symbol a("a"), b("b"), c("c"), x("x"), y("y");
+ ex ei, ef, ref;
+
+ ei = a*x + a*y;
+ ef = collect_common_factors(ei);
+ ref = (x+y)*a;
+ if (ef != ref) {
+ clog << "ERROR: collect_common_factors(" << ei << ") returned "
+ << ef << ", not " << ref << '.' << endl;
+ ++result;
+ }
+
+ ei = a*x*x + 2*a*x*y + a*y*y;
+ ef = collect_common_factors(ei);
+ ref = a*(x*x + 2*x*y + y*y);
+ if (ef != ref) {
+ clog << "ERROR: collect_common_factors(" << ei << ") returned "
+ << ef << ", not " << ref << '.' << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+static unsigned exam_collect_common_factors_zero()
+{
+ // r = 0 = c*0 = c*(x + 1 - 1 - x) = c*(x + 1) - c - c*x
+ // e = a*r - b*r
+ symbol a("a"), b("b"), c("c"), x("x");
+
+ ex r = c*(x+1) - c - c*x;
+ ex ei = a*r + b*r;
+ ex ef = collect_common_factors(ei);
+ if (!ef.is_zero()) {
+ clog << "ERROR: " << ei << " should be 0, got " << ef << " instead." << endl;
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ int result = 0;
+
+ cout << "examining collect_common_factors" << flush;
+
+ result += exam_collect_common_factors_simple(); cout << '.' << flush;
+ result += exam_collect_common_factors_zero(); cout << '.' << flush;
+
+ return result;
+}
* 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-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Tests for symbolic differentiation, including various functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Factorization test suite. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <iostream>
using namespace std;
-static symbol w("w"), x("x"), y("y"), z("z");
-
static unsigned check_factor(const ex& e)
{
ex ee = e.expand();
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);
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);
return result;
}
-static unsigned check_factorization(const exvector& factors)
+static unsigned exam_factor_magerya()
{
- ex e = dynallocate<mul>(factors);
- ex ef = factor(e.expand());
- if (ef.nops() != factors.size()) {
- clog << "wrong number of factors, expected " << factors.size() <<
- ", got " << ef.nops();
- return 1;
- }
- for (size_t i = 0; i < ef.nops(); ++i) {
- if (find(factors.begin(), factors.end(), ef.op(i)) == factors.end()) {
- clog << "wrong factorization: term not found: " << ef.op(i);
- return 1;
- }
- }
- return 0;
-}
+ // In 2017, Vitaly Magerya reported a class of biviariate polynomials
+ // where Hensel lifting sometimes failed to terminate.
+ // https://www.ginac.de/pipermail/ginac-list/2017-December/002162.html
+ unsigned result = 0;
+ ex e;
+ symbol x("x"), y("y");
-static unsigned factor_integer_content_bug()
-{
- parser reader;
- exvector factors;
- factors.push_back(reader("x+y+x*y"));
- factors.push_back(reader("3*x+2*y"));
- return check_factorization(factors);
+ e = (1+2*x+y)*(1+2*x-y)*(2*x-y)*(2*x+y);
+ result += check_factor_expanded(e);
+
+ e = (7+4*x+y)*(-5+2*x-y)*(-6+6*x+y)*y*(10+2*x+y);
+ result += check_factor_expanded(e);
+
+ e = (8+6*x-y)*(-5+4*x-y)*(-5+6*x+y)*(-2+2*x-y)*(2+4*x+y);
+ result += check_factor_expanded(e);
+
+ e = -(-4+4*x+5*y)*(1+4*x+5*y)*(2+3*y)*(1+2*x-y)*(4+2*x+y);
+ result += check_factor_expanded(e);
+
+ e = (-3+y-2*x)*(4+3*y-4*x)*(3+3*y+2*x)*(-2+3*y+2*x)*(-1+4*y+3*x);
+ result += check_factor_expanded(e);
+
+ e = (-9+7*x+y)*(-5+6*x+y)*(4+2*x+y)*(5+2*x-y)*(7+9*x-y)*(8+6*x-y);
+ result += check_factor_expanded(e);
+
+ e = pow(2*x-y,2)*(-1+6*x-y)*(-1+3*x-y)*(-2+4*x-y)*(1+4*x-y)*(4*x-y)*(2+4*x-y);
+ result += check_factor_expanded(e);
+
+ e = (5+2*y-3*x)*(-4+4*y+3*x)*(-3+4*y-2*x)*(4+5*y-x)*(3*y+2*x)*(-1+3*y+5*x)*(5+3*y+4*x);
+ result += check_factor_expanded(e);
+
+ return result;
}
unsigned exam_factor()
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;
}
--- /dev/null
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
+#include "ginac/ginac.h"
+#endif
+
+#include <vector>
+#include <iostream>
+
+using namespace GiNaC;
+using namespace std;
+
+DECLARE_FUNCTION_2P(foobar);
+
+static bool eval_called = false;
+static exvector eval_called_with = {};
+static bool evalf_called = false;
+static exvector evalf_called_with = {};
+
+static void reset() {
+ eval_called_with.clear();
+ evalf_called_with.clear();
+ evalf_called = false;
+ eval_called = false;
+}
+
+static ex foobar_eval(const exvector& args) {
+ eval_called = true;
+ for (auto const& v: args)
+ eval_called_with.push_back(v);
+
+ return foobar(args[0], args[1]).hold();
+}
+
+static ex foobar_evalf(const exvector& args) {
+ evalf_called = true;
+ for (auto const& v: args)
+ evalf_called_with.push_back(v);
+ return foobar(args[0], args[1]).hold();
+}
+
+
+REGISTER_FUNCTION(foobar, eval_func(foobar_eval).
+ evalf_func(foobar_evalf));
+
+static int check_exvector_eval() {
+ symbol x("x"), y("y");
+ int err = 1;
+
+ reset();
+ ex e = foobar(x, y);
+ if (!eval_called) {
+ clog << "*** Error: " << __func__ << ": foobar_eval hasn't been called" << endl;
+ err *= 2;
+ }
+ if (eval_called_with.size() != 2) {
+ clog << "*** Error: " << __func__ << ": fobar_eval: expected 2 arguments, got " <<
+ eval_called_with.size() << endl;
+ err *= 3;
+ }
+ if (eval_called_with[0] != x) {
+ clog << "*** Error: " << __func__ << ": fobar_eval: wrong 1st argument, "
+ "expected " << x << ", got " << eval_called_with[0] << endl;
+ err *= 5;
+ }
+ if (eval_called_with[1] != y) {
+ clog << "*** Error: " << __func__ << ": fobar_eval: wrong 1st argument, "
+ "expected " << y << ", got " << eval_called_with[1] << endl;
+ err *= 7;
+ }
+ return err - 1;
+}
+
+static int check_exvector_evalf() {
+ int err = 1;
+
+ reset();
+ ex e = foobar(Pi, Euler);
+ e = e.evalf();
+
+ if (!evalf_called) {
+ clog << "*** Error: " << __func__ << ": foobar_evalf hasn't been called" << endl;
+ err *= 2;
+ }
+ if (evalf_called_with.size() != 2) {
+ clog << __func__ << ": foobar_evalf: expected 2 arguments, got " <<
+ evalf_called_with.size() << endl;
+ err *= 3;
+ }
+ if (!is_a<numeric>(evalf_called_with[0])) {
+ clog << "*** Error: " << __func__ << ": wrong 1st argument of foobar_evalf: "
+ "expected a real number, got " << evalf_called_with[0] << endl;
+ err *= 5;
+ }
+ if (!is_a<numeric>(evalf_called_with[1])) {
+ clog << "*** Error: " << __func__ << ": wrong 1st argument of foobar_evalf: "
+ "expected a real number, got " << evalf_called_with[0] << endl;
+ err *= 7;
+ }
+ return err - 1;
+}
+
+int main(int argc, char** argv) {
+ int ret = 0;
+ auto err = check_exvector_evalf();
+ if (err) {
+ ret |= 1;
+ clog << "*** Error " << (err + 1) << " (check_exvector_evalf)" << endl;
+ }
+ err = check_exvector_eval();
+ if (err) {
+ ret |= 2;
+ clog << "*** Error " << (err + 1) << " (check_exvector_evalf)" << endl;
+ }
+ return ret;
+}
/** @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-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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);
* Here we test manipulations on GiNaC's indexed objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- /dev/null
+/** @file exam_inifcns_nstdsums.cpp
+ *
+ * This test routine applies assorted tests on initially known higher level
+ * functions. */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+#include <fstream>
+using namespace std;
+
+
+static unsigned check_q_expansion()
+{
+ unsigned err = 0;
+
+ symbol q("q");
+ int order = 200;
+
+ ex res;
+
+ // q-expansions from Sage up to order 200
+ // notation Ek_N_|a|_|b|_K
+ ex E1_12_1_4_1 = pow(q,2)+pow(q,4)+2*pow(q,5)+pow(q,8)+pow(q,9)+2*pow(q,10)+2*pow(q,13)+pow(q,16)+2*pow(q,17)+pow(q,18)+2*pow(q,20)+3*pow(q,25)+2*pow(q,26)
+ +2*pow(q,29)+pow(q,32)+2*pow(q,34)+pow(q,36)+2*pow(q,37)+2*pow(q,40)+2*pow(q,41)+2*pow(q,45)+pow(q,49)+3*pow(q,50)+2*pow(q,52)+2*pow(q,53)+2*pow(q,58)
+ +2*pow(q,61)+pow(q,64)+4*pow(q,65)+2*pow(q,68)+pow(q,72)+2*pow(q,73)+2*pow(q,74)+2*pow(q,80)+pow(q,81)+2*pow(q,82)+4*pow(q,85)+2*pow(q,89)+2*pow(q,90)
+ +2*pow(q,97)+pow(q,98)+3*pow(q,100)+2*pow(q,101)+2*pow(q,104)+2*pow(q,106)+2*pow(q,109)+2*pow(q,113)+2*pow(q,116)+2*pow(q,117)+pow(q,121)+2*pow(q,122)
+ +4*pow(q,125)+pow(q,128)+4*pow(q,130)+2*pow(q,136)+2*pow(q,137)+pow(q,144)+4*pow(q,145)+2*pow(q,146)+2*pow(q,148)+2*pow(q,149)+2*pow(q,153)+2*pow(q,157)
+ +2*pow(q,160)+pow(q,162)+2*pow(q,164)+3*pow(q,169)+4*pow(q,170)+2*pow(q,173)+2*pow(q,178)+2*pow(q,180)+2*pow(q,181)+4*pow(q,185)+2*pow(q,193)
+ +2*pow(q,194)+pow(q,196)+2*pow(q,197)+numeric(1,4)+q;
+
+ ex E1_12_1_4_3 = numeric(1,4)+pow(q,3)+pow(q,6)+pow(q,12)+2*pow(q,15)+pow(q,24)+pow(q,27)+2*pow(q,30)+2*pow(q,39)+pow(q,48)+2*pow(q,51)+pow(q,54)+2*pow(q,60)
+ +3*pow(q,75)+2*pow(q,78)+2*pow(q,87)+pow(q,96)+2*pow(q,102)+pow(q,108)+2*pow(q,111)+2*pow(q,120)+2*pow(q,123)+2*pow(q,135)+pow(q,147)+3*pow(q,150)
+ +2*pow(q,156)+2*pow(q,159)+2*pow(q,174)+2*pow(q,183)+pow(q,192)+4*pow(q,195);
+
+ ex E1_12_1_3_1 = 2*pow(q,175)+2*pow(q,189)+2*pow(q,199)+numeric(1,6)+2*pow(q,129)+4*pow(q,133)+2*pow(q,139)+2*pow(q,151)+2*pow(q,163)+2*pow(q,171)+2*pow(q,172)
+ +2*pow(q,31)+2*pow(q,43)+2*pow(q,57)+2*pow(q,63)+2*pow(q,67)+2*pow(q,76)+2*pow(q,79)+2*pow(q,84)+4*pow(q,91)+2*pow(q,93)+2*pow(q,103)+2*pow(q,112)
+ +2*pow(q,124)+2*pow(q,127)+pow(q,4)+pow(q,9)+2*pow(q,13)+pow(q,16)+pow(q,25)+pow(q,36)+2*pow(q,37)+3*pow(q,49)+2*pow(q,52)+2*pow(q,61)+pow(q,64)
+ +2*pow(q,73)+pow(q,81)+2*pow(q,97)+pow(q,100)+2*pow(q,109)+2*pow(q,117)+pow(q,121)+pow(q,144)+2*pow(q,148)+2*pow(q,157)+3*pow(q,169)+2*pow(q,181)
+ +2*pow(q,193)+3*pow(q,196)+pow(q,3)+pow(q,12)+pow(q,27)+2*pow(q,39)+pow(q,48)+pow(q,75)+pow(q,108)+2*pow(q,111)+3*pow(q,147)+2*pow(q,156)+2*pow(q,183)
+ +pow(q,192)+2*pow(q,7)+2*pow(q,19)+2*pow(q,21)+2*pow(q,28)+q;
+
+ ex E1_12_1_3_2 = numeric(1,6)+pow(q,2)+pow(q,8)+pow(q,18)+2*pow(q,26)+pow(q,32)+pow(q,50)+pow(q,72)+2*pow(q,74)+3*pow(q,98)+2*pow(q,104)+2*pow(q,122)+pow(q,128)
+ +2*pow(q,146)+pow(q,162)+2*pow(q,194)+pow(q,6)+pow(q,24)+pow(q,54)+2*pow(q,78)+pow(q,96)+pow(q,150)+2*pow(q,14)+2*pow(q,38)+2*pow(q,42)+2*pow(q,56)
+ +2*pow(q,62)+2*pow(q,86)+2*pow(q,114)+2*pow(q,126)+2*pow(q,134)+2*pow(q,152)+2*pow(q,158)+2*pow(q,168)+4*pow(q,182)+2*pow(q,186);
+
+ ex E1_12_1_3_4 = numeric(1,6)+pow(q,4)+pow(q,12)+pow(q,16)+2*pow(q,28)+pow(q,36)+pow(q,48)+2*pow(q,52)+pow(q,64)+2*pow(q,76)+2*pow(q,84)+pow(q,100)+pow(q,108)
+ +2*pow(q,112)+2*pow(q,124)+pow(q,144)+2*pow(q,148)+2*pow(q,156)+2*pow(q,172)+pow(q,192)+3*pow(q,196);
+
+
+ ex E2_12_1_1_2 = 248*pow(q,175)+320*pow(q,189)+200*pow(q,199)+176*pow(q,129)+160*pow(q,133)+140*pow(q,139)+152*pow(q,151)+164*pow(q,163)+260*pow(q,171)
+ +44*pow(q,172)+32*pow(q,31)+44*pow(q,43)+80*pow(q,57)+104*pow(q,63)+68*pow(q,67)+20*pow(q,76)+80*pow(q,79)+32*pow(q,84)+112*pow(q,91)+128*pow(q,93)
+ +104*pow(q,103)+8*pow(q,112)+32*pow(q,124)+128*pow(q,127)+pow(q,2)+pow(q,4)+6*pow(q,5)+pow(q,8)+13*pow(q,9)+6*pow(q,10)+14*pow(q,13)+pow(q,16)
+ +18*pow(q,17)+13*pow(q,18)+6*pow(q,20)+31*pow(q,25)+14*pow(q,26)+30*pow(q,29)+pow(q,32)+18*pow(q,34)+13*pow(q,36)+38*pow(q,37)+6*pow(q,40)+42*pow(q,41)
+ +78*pow(q,45)+57*pow(q,49)+31*pow(q,50)+14*pow(q,52)+54*pow(q,53)+30*pow(q,58)+62*pow(q,61)+pow(q,64)+84*pow(q,65)+18*pow(q,68)+13*pow(q,72)+74*pow(q,73)
+ +38*pow(q,74)+6*pow(q,80)+121*pow(q,81)+42*pow(q,82)+108*pow(q,85)+90*pow(q,89)+78*pow(q,90)+98*pow(q,97)+57*pow(q,98)+31*pow(q,100)+102*pow(q,101)
+ +14*pow(q,104)+54*pow(q,106)+110*pow(q,109)+114*pow(q,113)+30*pow(q,116)+182*pow(q,117)+133*pow(q,121)+62*pow(q,122)+156*pow(q,125)+pow(q,128)+84*pow(q,130)
+ +18*pow(q,136)+138*pow(q,137)+13*pow(q,144)+180*pow(q,145)+74*pow(q,146)+38*pow(q,148)+150*pow(q,149)+234*pow(q,153)+158*pow(q,157)+6*pow(q,160)+121*pow(q,162)
+ +42*pow(q,164)+183*pow(q,169)+108*pow(q,170)+174*pow(q,173)+90*pow(q,178)+78*pow(q,180)+182*pow(q,181)+228*pow(q,185)+194*pow(q,193)+98*pow(q,194)+57*pow(q,196)
+ +198*pow(q,197)+4*pow(q,3)+4*pow(q,6)+4*pow(q,12)+24*pow(q,15)+4*pow(q,24)+40*pow(q,27)+24*pow(q,30)+56*pow(q,39)+4*pow(q,48)+72*pow(q,51)+40*pow(q,54)
+ +24*pow(q,60)+124*pow(q,75)+56*pow(q,78)+120*pow(q,87)+4*pow(q,96)+72*pow(q,102)+40*pow(q,108)+152*pow(q,111)+24*pow(q,120)+168*pow(q,123)+240*pow(q,135)
+ +228*pow(q,147)+124*pow(q,150)+56*pow(q,156)+216*pow(q,159)+120*pow(q,174)+248*pow(q,183)+4*pow(q,192)+336*pow(q,195)+8*pow(q,7)+20*pow(q,19)+32*pow(q,21)
+ +8*pow(q,28)+8*pow(q,14)+20*pow(q,38)+32*pow(q,42)+8*pow(q,56)+32*pow(q,62)+44*pow(q,86)+80*pow(q,114)+104*pow(q,126)+68*pow(q,134)+20*pow(q,152)+80*pow(q,158)
+ +32*pow(q,168)+112*pow(q,182)+128*pow(q,186)+12*pow(q,11)+12*pow(q,22)+24*pow(q,23)+48*pow(q,33)+48*pow(q,35)+12*pow(q,44)+24*pow(q,46)+48*pow(q,47)+72*pow(q,55)
+ +60*pow(q,59)+48*pow(q,66)+96*pow(q,69)+48*pow(q,70)+72*pow(q,71)+96*pow(q,77)+84*pow(q,83)+12*pow(q,88)+24*pow(q,92)+48*pow(q,94)+120*pow(q,95)+156*pow(q,99)
+ +192*pow(q,105)+108*pow(q,107)+72*pow(q,110)+144*pow(q,115)+60*pow(q,118)+144*pow(q,119)+132*pow(q,131)+48*pow(q,132)+96*pow(q,138)+48*pow(q,140)+192*pow(q,141)
+ +72*pow(q,142)+168*pow(q,143)+96*pow(q,154)+192*pow(q,155)+192*pow(q,161)+288*pow(q,165)+84*pow(q,166)+168*pow(q,167)+12*pow(q,176)+240*pow(q,177)+180*pow(q,179)
+ +24*pow(q,184)+216*pow(q,187)+48*pow(q,188)+120*pow(q,190)+192*pow(q,191)+156*pow(q,198)+numeric(1,24)+q;
+
+ ex E3_12_3_1_4 = 1850*pow(q,172)+362*pow(q,76)+450*pow(q,84)+650*pow(q,112)+962*pow(q,124)+pow(q,4)+3*pow(q,8)+13*pow(q,16)+24*pow(q,20)+51*pow(q,32)+81*pow(q,36)
+ +72*pow(q,40)+170*pow(q,52)+205*pow(q,64)+288*pow(q,68)+243*pow(q,72)+312*pow(q,80)+601*pow(q,100)+510*pow(q,104)+840*pow(q,116)+819*pow(q,128)+864*pow(q,136)
+ +1053*pow(q,144)+1370*pow(q,148)+1224*pow(q,160)+1680*pow(q,164)+1944*pow(q,180)+2451*pow(q,196)+9*pow(q,12)+27*pow(q,24)+117*pow(q,48)+216*pow(q,60)
+ +459*pow(q,96)+729*pow(q,108)+648*pow(q,120)+1530*pow(q,156)+1845*pow(q,192)+50*pow(q,28)+150*pow(q,56)+1086*pow(q,152)+1350*pow(q,168)+120*pow(q,44)
+ +360*pow(q,88)+528*pow(q,92)+1080*pow(q,132)+1200*pow(q,140)+1560*pow(q,176)+1584*pow(q,184)+2208*pow(q,188);
+
+ // basis of Eisenstein space for Gamma_1(12) of weight 1
+ res = series_to_poly(Eisenstein_kernel(1, 12, 1, -3, 1).q_expansion_modular_form(q, order)) - E1_12_1_3_1;
+ if ( res != 0 ) err++;
+
+ res = series_to_poly(Eisenstein_kernel(1, 12, 1, -3, 2).q_expansion_modular_form(q, order)) - E1_12_1_3_2;
+ if ( res != 0 ) err++;
+
+ res = series_to_poly(Eisenstein_kernel(1, 12, 1, -3, 4).q_expansion_modular_form(q, order)) - E1_12_1_3_4;
+ if ( res != 0 ) err++;
+
+ res = series_to_poly(Eisenstein_kernel(1, 12, 1, -4, 1).q_expansion_modular_form(q, order)) - E1_12_1_4_1;
+ if ( res != 0 ) err++;
+
+ res = series_to_poly(Eisenstein_kernel(1, 12, 1, -4, 3).q_expansion_modular_form(q, order)) - E1_12_1_4_3;
+ if ( res != 0 ) err++;
+
+ // test one series of weight 2
+ res = series_to_poly(Eisenstein_kernel(2, 12, 1, 1, 2).q_expansion_modular_form(q, order)) - E2_12_1_1_2;
+ if ( res != 0 ) err++;
+
+ // and one of weight 3
+ res = series_to_poly(Eisenstein_kernel(3, 12, -3, 1, 4).q_expansion_modular_form(q, order)) - E3_12_3_1_4;
+ if ( res != 0 ) err++;
+
+ return err;
+}
+
+static unsigned check_polylogs()
+{
+ unsigned err = 0;
+
+ int digitsbuf = Digits;
+ Digits = 100;
+ ex prec = 5 * pow(10, -(ex)Digits);
+
+ ex y = numeric(9,10);
+
+ ex z2 = numeric(2);
+ ex z3 = numeric(3);
+
+ ex L0 = basic_log_kernel();
+ ex omega_2 = multiple_polylog_kernel(z2);
+ ex omega_3 = multiple_polylog_kernel(z3);
+
+ ex res1,res2;
+
+ res1 = G(lst{z2},y).evalf();
+ res2 = iterated_integral(lst{omega_2},y).evalf();
+ if ( abs(res1-res2) > prec ) err++;
+
+ res1 = G(lst{0},y).evalf();
+ res2 = iterated_integral(lst{L0},y).evalf();
+ if ( abs(res1-res2) > prec ) err++;
+
+ res1 = G(lst{z2,0},y).evalf();
+ res2 = iterated_integral(lst{omega_2,L0},y).evalf();
+ if ( abs(res1-res2) > prec ) err++;
+
+ res1 = G(lst{0,0},y).evalf();
+ res2 = iterated_integral(lst{L0,L0},y).evalf();
+ if ( abs(res1-res2) > prec ) err++;
+
+ res1 = G(lst{z2,0,0},y).evalf();
+ res2 = iterated_integral(lst{omega_2,L0,L0},y).evalf();
+ if ( abs(res1-res2) > prec ) err++;
+
+ Digits = digitsbuf;
+
+ return err;
+}
+
+static unsigned check_iterated_integral_modular_form_versus_Kronecker_dtau()
+{
+ unsigned err = 0;
+
+ int digitsbuf = Digits;
+ Digits = 30;
+ ex prec = 5 * pow(10, -(ex)Digits);
+
+ ex tau_6 = I;
+ ex qbar_6 = exp(2*Pi*I*tau_6);
+ ex omega_0 = basic_log_kernel();
+
+ ex eta_1 = Eisenstein_kernel(3, 6, -3, 1, 1);
+ ex eta_2 = Eisenstein_kernel(3, 6, -3, 1, 2);
+ ex omega_3 = modular_form_kernel(3, eta_1-8*eta_2);
+ ex res1 = iterated_integral(lst{omega_0,omega_3},qbar_6).evalf();
+
+ ex C_3 = I/sqrt(numeric(3));
+ ex g3_1 = Kronecker_dtau_kernel(3,numeric(1,3),1,C_3);
+ ex g3_2 = Kronecker_dtau_kernel(3,numeric(1,3),2,C_3);
+ ex expr = iterated_integral(lst{omega_0,g3_1},qbar_6) - 4*iterated_integral(lst{omega_0,g3_2},qbar_6);
+ ex res2 = expr.evalf();
+
+ if ( abs(res1-res2) > prec ) err++;
+
+ Digits = digitsbuf;
+
+ return err;
+}
+
+static unsigned check_modular_trafo()
+{
+ unsigned err = 0;
+
+ int digitsbuf = Digits;
+ Digits = 50;
+ ex prec = 5 * pow(10, -(ex)Digits);
+
+ int N_trunc = 100;
+
+ int a = 0;
+ int b = -1;
+ int c = 1;
+ int d = 0;
+
+ ex tau = numeric(1,10)+numeric(4,5)*I;
+ ex qbar = evalf(exp(2*Pi*I*tau));
+ ex qbar_2 = evalf(exp(2*Pi*I*tau*numeric(1,2)));
+ ex qbar_3 = evalf(exp(2*Pi*I*tau*numeric(1,3)));
+ ex qbar_4 = evalf(exp(2*Pi*I*tau*numeric(1,4)));
+ ex qbar_6 = evalf(exp(2*Pi*I*tau*numeric(1,6)));
+ ex qbar_12 = evalf(exp(2*Pi*I*tau*numeric(1,12)));
+
+ ex tau_prime = (a*tau+b)/(c*tau+d);
+ ex qbar_prime = evalf(exp(2*Pi*I*tau_prime));
+ ex qbar_prime_2 = evalf(exp(2*Pi*I*tau_prime*numeric(1,2)));
+ ex qbar_prime_3 = evalf(exp(2*Pi*I*tau_prime*numeric(1,3)));
+ ex qbar_prime_4 = evalf(exp(2*Pi*I*tau_prime*numeric(1,4)));
+ ex qbar_prime_6 = evalf(exp(2*Pi*I*tau_prime*numeric(1,6)));
+ ex qbar_prime_12 = evalf(exp(2*Pi*I*tau_prime*numeric(1,12)));
+
+ numeric k,N,r,s;
+ ex eta,eta_trafo,res1,res2;
+
+ k = 4;
+ N = 1;
+ eta = Eisenstein_kernel(k, N, 1, 1, 1);
+ res1 = ex_to<Eisenstein_kernel>(eta).get_numerical_value(qbar_prime,N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_kernel>(eta).get_numerical_value(qbar,N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 4;
+ N = 2;
+ r = 0;
+ s = 0;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_2,N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_2,N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 4;
+ N = 2;
+ r = 1;
+ s = 1;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_2,N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_2,N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 4;
+ N = 4;
+ r = 2;
+ s = 2;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_4,N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_4,N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 4;
+ N = 6;
+ r = 3;
+ s = 3;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_6,3*N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_6,3*N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 4;
+ N = 12;
+ r = 6;
+ s = 6;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_12,6*N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_12,6*N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 4;
+ N = 2;
+ r = 1;
+ s = 0;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_2,N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_2,N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 6;
+ N = 6;
+ r = 1;
+ s = 5;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_6,2*N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_6,2*N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 6;
+ N = 12;
+ r = 2;
+ s = 10;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_12,4*N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_12,4*N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 4;
+ N = 3;
+ r = 1;
+ s = 2;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_3,N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_3,N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ k = 1;
+ N = 6;
+ r = 1;
+ s = 5;
+ eta = Eisenstein_h_kernel(k, N, r, s);
+ eta_trafo = Eisenstein_h_kernel(k, N, mod(r*d+s*b,N), mod(r*c+s*a,N));
+ res1 = ex_to<Eisenstein_h_kernel>(eta).get_numerical_value(qbar_prime_6,2*N_trunc);
+ res2 = pow(c*tau+d,k)*ex_to<Eisenstein_h_kernel>(eta_trafo).get_numerical_value(qbar_6,2*N_trunc);
+ if ( abs(res1-res2) > prec ) err++;
+
+ Digits = digitsbuf;
+
+ return err;
+}
+
+static unsigned check_Kronecker_g()
+{
+ unsigned err = 0;
+
+ int digitsbuf = Digits;
+ Digits = 20;
+ ex prec = 5 * pow(10, -(ex)Digits);
+
+ ex tau = numeric(1,10)+numeric(2)*I;
+ ex qbar = evalf(exp(2*Pi*I*tau));
+
+ ex z = numeric(2,100)+numeric(1,10)*I;
+ ex wbar = evalf(exp(2*Pi*I*z));
+
+ ex z_j = numeric(-1,10)*I;
+
+ ex res1,res2,res3;
+
+ res1 = Kronecker_dtau_kernel(0,z).get_numerical_value(qbar);
+ res2 = Kronecker_dz_kernel(1,0,tau).get_numerical_value(z);
+ res3 = Kronecker_dz_kernel(1,z_j,tau).get_numerical_value(z+z_j);
+ if ( abs(res1-res2) > prec ) err++;
+ if ( abs(res1-res3) > prec ) err++;
+
+ res1 = Kronecker_dtau_kernel(1,z).get_numerical_value(qbar);
+ res2 = Kronecker_dz_kernel(2,0,tau).get_numerical_value(z);
+ res3 = Kronecker_dz_kernel(2,z_j,tau).get_numerical_value(z+z_j);
+ if ( abs(res1-res2) > prec ) err++;
+ if ( abs(res1-res3) > prec ) err++;
+
+ res1 = Kronecker_dtau_kernel(2,z).get_numerical_value(qbar);
+ res2 = Kronecker_dz_kernel(3,0,tau).get_numerical_value(z);
+ res3 = Kronecker_dz_kernel(3,z_j,tau).get_numerical_value(z+z_j);
+ if ( abs(res1-res2) > prec ) err++;
+ if ( abs(res1-res3) > prec ) err++;
+
+ res1 = Kronecker_dtau_kernel(3,z).get_numerical_value(qbar);
+ res2 = Kronecker_dz_kernel(4,0,tau).get_numerical_value(z);
+ res3 = Kronecker_dz_kernel(4,z_j,tau).get_numerical_value(z+z_j);
+ if ( abs(res1-res2) > prec ) err++;
+ if ( abs(res1-res3) > prec ) err++;
+
+ res1 = Kronecker_dtau_kernel(4,z).get_numerical_value(qbar);
+ res2 = Kronecker_dz_kernel(5,0,tau).get_numerical_value(z);
+ res3 = Kronecker_dz_kernel(5,z_j,tau).get_numerical_value(z+z_j);
+ if ( abs(res1-res2) > prec ) err++;
+ if ( abs(res1-res3) > prec ) err++;
+
+ res1 = Kronecker_dtau_kernel(5,z).get_numerical_value(qbar);
+ res2 = Kronecker_dz_kernel(6,0,tau).get_numerical_value(z);
+ res3 = Kronecker_dz_kernel(6,z_j,tau).get_numerical_value(z+z_j);
+ if ( abs(res1-res2) > prec ) err++;
+ if ( abs(res1-res3) > prec ) err++;
+
+ Digits = digitsbuf;
+
+ return err;
+}
+
+unsigned exam_inifcns_elliptic(void)
+{
+ unsigned result = 0;
+
+ cout << "examining consistency of iterated integrals" << flush;
+
+ result += check_q_expansion();
+ result += check_polylogs();
+ result += check_iterated_integral_modular_form_versus_Kronecker_dtau();
+ result += check_modular_trafo();
+ result += check_Kronecker_g();
+
+ return result;
+}
+
+int main(int argc, char** argv)
+{
+ return exam_inifcns_elliptic();
+}
* functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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;
* Comparison data for the test of polylogarithms. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* These exams test solving small linear systems of symbolic equations. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
-/** @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-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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:
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);
* Here we examine manipulations on GiNaC's symbolic matrices. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
bool caught = false;
try {
m5 = inverse(m4);
- } catch (std::runtime_error err) {
+ } catch (std::runtime_error &err) {
caught = true;
}
if (!caught) {
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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
++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;
}
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;
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;
}
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Rational function normalization test suite. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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;
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;
}
* tests on these numbers like is_integer() etc... */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* these oopses for good, so we run those stupid tests... */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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;
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()
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;
}
--- /dev/null
+/** @file parser_bugs.cpp
+ *
+ * Check for some silly bugs in the parser. */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+using namespace std;
+
+// - a - b was misparsed as -a + b due to a bug in parser::parse_unary_expr()
+static int check1(ostream& err_str)
+{
+ const string srep("-a-b");
+ parser reader;
+ ex e = reader(srep);
+ ex a = reader.get_syms()["a"];
+ ex b = reader.get_syms()["b"];
+ ex g = - a - b;
+ ex d = (e - g).expand();
+ if (!d.is_zero()) {
+ err_str << "\"" << srep << "\" was misparsed as \""
+ << e << "\"" << endl;
+ return 1;
+ }
+ return 0;
+}
+
+/// Parser was rejecting the valid expression '5 - (3*x)/10'.
+static int check2(ostream& err_str)
+{
+ const string srep("5-(3*x)/10");
+ parser reader;
+ ex e = reader(srep);
+ ex x = reader.get_syms()["x"];
+ ex g = 5 - (3*x)/10;
+ ex d = (e - g).expand();
+ if (!d.is_zero()) {
+ err_str << "\"" << srep << "\" was misparsed as \""
+ << e << "\"" << endl;
+ return 1;
+ }
+ return 0;
+}
+
+/// parse_literal_expr forget to consume the token, so parser get
+/// very confused.
+static int check3(ostream& err_str)
+{
+ const string srep("5-(2*I)/3");
+ parser reader;
+ ex e = reader(srep);
+ ex g = numeric(5) - (numeric(2)*I)/3;
+ ex d = (e - g).expand();
+ if (!d.is_zero()) {
+ err_str << "\"" << srep << "\" was misparsed as \""
+ << e << "\"" << endl;
+ return 1;
+ }
+ return 0;
+}
+
+/// parser happily accepted various junk like 'x^2()+1'
+static int check4(ostream& err_str)
+{
+ const string junk("x^2()+1");
+ parser reader;
+ ex e;
+ try {
+ e = reader(junk);
+ err_str << "parser accepts junk: \"" << junk << "\"" << endl;
+ return 1;
+ } catch (parse_error& err) {
+ // Ok, parser rejects the nonsense.
+ return 0;
+ }
+}
+
+// Check that two strings parse to equal expressions.
+static int check_eq(ostream &err_str, parser &reader, const char *expr1, const char *expr2)
+{
+ const string srep1(expr1);
+ const string srep2(expr2);
+ ex e1, e2;
+ try{ e1 = reader(srep1); } catch (const exception &e) {
+ err_str << "\"" << srep1 << "\" failed to parse: "
+ << e.what() << endl;
+ return 1;
+ }
+ try{ e2 = reader(srep2); } catch (const exception &e) {
+ err_str << "\"" << srep2 << "\" failed to parse: "
+ << e.what() << endl;
+ return 1;
+ }
+ if (!(e1-e2).expand().is_zero()) {
+ err_str << "\"" << srep1 << "\" was misparsed as \""
+ << e1 << "\"" << endl;
+ return 1;
+ }
+ return 0;
+}
+
+// Tests for the interaction of the '^' operator with
+// the unary '+' and the unary '-' operators
+static int check5(ostream& err_str)
+{
+ parser reader;
+ return
+ +check_eq(err_str, reader, "3^2+1", "10")
+ +check_eq(err_str, reader, "3^+2-1", "8")
+ +check_eq(err_str, reader, "3^-2+1", "10/9")
+ +check_eq(err_str, reader, "3^-2/5", "1/45")
+ +check_eq(err_str, reader, "3^-2*5", "5/9")
+ +check_eq(err_str, reader, "3^-2-5", "-44/9")
+ +check_eq(err_str, reader, "3^(-2)+1", "10/9")
+ +check_eq(err_str, reader, "(3)^(-2)+1", "10/9")
+ +check_eq(err_str, reader, "+3^2+1", "10")
+ +check_eq(err_str, reader, "+3^+2+1", "10")
+ +check_eq(err_str, reader, "+3^-2+1", "10/9")
+ +check_eq(err_str, reader, "+3^-2/5", "1/45")
+ +check_eq(err_str, reader, "+3^-2*5", "5/9")
+ +check_eq(err_str, reader, "+3^-2-5", "-44/9")
+ +check_eq(err_str, reader, "-3^2+1", "-8")
+ +check_eq(err_str, reader, "-3^+2+1", "-8")
+ +check_eq(err_str, reader, "-3^-2+1", "8/9")
+ +check_eq(err_str, reader, "-3^-2/3", "-1/27")
+ +check_eq(err_str, reader, "1+2^3^4", "1+(2^81)")
+ +check_eq(err_str, reader, "2^3^4+1", "1+(2^81)")
+ +check_eq(err_str, reader, "2^+3^4+1", "1+(2^81)")
+ +check_eq(err_str, reader, "2^3^+4+1", "1+(2^81)");
+}
+
+// Tests for the interaction of the '*' operator with
+// the unary '+' and the unary '-' operators
+static int check6(ostream& err_str)
+{
+ parser reader;
+ return
+ +check_eq(err_str, reader, "3*+2-1", "5")
+ +check_eq(err_str, reader, "3*2+1", "7")
+ +check_eq(err_str, reader, "3*+2+1", "7")
+ +check_eq(err_str, reader, "3*-2+1", "-5")
+ +check_eq(err_str, reader, "3*-2/5", "-6/5")
+ +check_eq(err_str, reader, "3*-2*5", "-30")
+ +check_eq(err_str, reader, "3*-2-5", "-11")
+ +check_eq(err_str, reader, "3*(-2)+1", "-5")
+ +check_eq(err_str, reader, "(3)*(-2)+1", "-5")
+ +check_eq(err_str, reader, "+3*2+1", "7")
+ +check_eq(err_str, reader, "+3*+2+1", "7")
+ +check_eq(err_str, reader, "+3*-2+1", "-5")
+ +check_eq(err_str, reader, "+3*-2/5", "-6/5")
+ +check_eq(err_str, reader, "+3*-2*5", "-30")
+ +check_eq(err_str, reader, "+3*-2-5", "-11")
+ +check_eq(err_str, reader, "-3*2+1", "-5")
+ +check_eq(err_str, reader, "-3*+2+1", "-5")
+ +check_eq(err_str, reader, "-3*-2+1", "7")
+ +check_eq(err_str, reader, "-3*-2/3", "2")
+ +check_eq(err_str, reader, "1+2*3*4", "25")
+ +check_eq(err_str, reader, "2*3*4+1", "25")
+ +check_eq(err_str, reader, "2*+3*4+1", "25")
+ +check_eq(err_str, reader, "2*3*+4+1", "25");
+}
+
+// Tests for nested unary + and unary -
+static int check7(ostream& err_str)
+{
+ parser reader;
+ return
+ +check_eq(err_str, reader, "+1", "1")
+ +check_eq(err_str, reader, "++1", "1")
+ +check_eq(err_str, reader, "+-+1", "-1")
+ +check_eq(err_str, reader, "+-+-1", "1")
+ +check_eq(err_str, reader, "+-+-+1", "1")
+ +check_eq(err_str, reader, "100++--+1+10", "111");
+}
+
+int main(int argc, char** argv)
+{
+ cout << "examining old parser bugs" << flush;
+ ostringstream err_str;
+ int errors = 0;
+ errors += check1(err_str); cout << '.' << flush;
+ errors += check2(err_str); cout << '.' << flush;
+ errors += check3(err_str); cout << '.' << flush;
+ errors += check4(err_str); cout << '.' << flush;
+ errors += check5(err_str); cout << '.' << flush;
+ errors += check6(err_str); cout << '.' << flush;
+ errors += check7(err_str); cout << '.' << flush;
+ if (errors) {
+ cout << "Yes, unfortunately:" << endl;
+ cout << err_str.str();
+ } else {
+ cout << "Not found. ";
+ }
+ return errors;
+}
--- /dev/null
+/** @file exam_pgcd.cpp
+ *
+ * Exam GCD over prime fields computations.
+ */
+#include <string>
+#include <iostream>
+#include <utility>
+#include "ginac.h"
+using namespace std;
+using namespace GiNaC;
+
+// Check for an infite loop in PGCD, fixed 2010-02-23.
+static unsigned pgcd_relatively_prime_bug()
+{
+ const symbol q("q");
+ parser reader;
+ reader.get_syms().insert(make_pair(string("q"), q));
+
+ ex t = reader("-E20^16*E4^8*E5^8*E1^16*q^4"
+ "-(E10^24-E20^8*E5^16)*E4^16*E1^8"
+ "+E2^24*E20^16*E5^8*q^4");
+ ex g = gcd(t.expand(), t.diff(q).expand()) - 1;
+ if (!g.is_zero()) {
+ clog << " oops!" << endl <<
+ "** Error: should be 0, got " << g << endl;
+ return 1;
+ }
+ return 0;
+}
+
+// Check for an infinite loop in PGCD, fixed 2010-03-18.
+static unsigned pgcd_infinite_loop()
+{
+ parser the_parser;
+ ex e = the_parser(string(R"ex(792*z^8*w^4*x^3*y^4*u^7
++ 24*z^4*w^4*x^2*y^3*u^4 + 264*z^8*w^3*x^2*y^7*u^5 + 198*z^4*w^5*x^5*y*u^6
++ 110*z^2*w^3*x^5*y^4*u^6 - 120*z^8*w*x^4*u^6 - 480*z^5*w*x^4*y^6*u^8
+- 720*z^7*x^3*y^3*u^7 + 165*z^4*w^2*x^4*y*u^5 + 450*z^8*w^6*x^2*y*u^8
++ 40*z^2*w^3*x^3*y^3*u^6 - 288*z^7*w^2*x^3*y^6*u^6 + 250*z^6*w^4*x^2*y^4*u^8
++ 576*z^7*w^7*x^2*y^4*u^8 - 80*z^6*w^2*x^5*y^3*u^7 - 144*z^8*w^4*x^5*u^7
++ 120*z^4*w*x^2*y^6*u^6 + 320*z^5*w^5*x^2*y^7*u^8 + 192*z^7*w^6*x*y^7*u^6
+- 12*z^4*w^3*x^3*y^5*u^6 - 36*z^4*w^4*x^4*y^2*u^8 + 72*z^4*w^5*x^3*u^6
+- 20*z^2*w^2*x^4*y^5*u^8 + 660*z^8*w*x^2*y^4*u^6 + 66*z^4*w^4*x^4*y^4*u^4
++ 440*z^6*w^2*x^3*y^7*u^7 - 30*z^4*w*x^3*y^2*u^7 - 48*z^8*w^3*x^4*y^3*u^5
++ 72*z^6*w^2*x*y^6*u^4 - 864*z^7*w^3*x^4*y^3*u^8 + 480*z^7*w^4*x*y^4*u^7
++ 60*z^4*w^2*x^2*u^5 + 375*z^8*w^3*x*y*u^7 + 150*z^8*w^5*x*y^4*u^6
++ 180*z^6*x*y^3*u^5 + 216*z^6*w^3*x^2*y^3*u^6)ex"));
+ const symbol x = ex_to<symbol>(the_parser.get_syms()["x"]);
+ ex g = gcd(e, e.diff(x));
+ ex should_be = the_parser(string("u^4*z^2"));
+ if (!(g-should_be).expand().is_zero()) {
+ clog << "GCD was miscomputed. " << endl;
+ return 1;
+ }
+ return 0;
+}
+
+int main()
+{
+ unsigned result = 0;
+
+ cout << "Examining pgcd() bugs (infinite loop, miscalculation)" << flush;
+
+ result += pgcd_relatively_prime_bug(); cout << '.' << flush;
+ result += pgcd_infinite_loop(); cout << '.' << flush;
+
+ return result;
+}
* rational function normalization in normalization.cpp. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Series expansion test (Laurent and Taylor series). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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;
result += exam_series12(); cout << '.' << flush;
result += exam_series13(); cout << '.' << flush;
result += exam_series14(); cout << '.' << flush;
+ result += exam_series15(); cout << '.' << flush;
return result;
}
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- /dev/null
+/** @file exam_relational.cpp
+ *
+ * Small test for the relational objects and their conversion to bool. */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+using namespace std;
+
+// Elementary relations should fall back to numeric comparisons.
+static unsigned exam_relational_elementary()
+{
+ unsigned result = 0;
+ ex one = 1, two = 2;
+
+ if (one == two) {
+ clog << "'" << one << " == " << two << "' was converted to true." << endl;
+ result += 1;
+ }
+ if (!(one != two)) {
+ clog << "'" << one << " != " << two << "' was not converted to true." << endl;
+ result += 1;
+ }
+ if (!(one < two)) {
+ clog << "'" << one << " < " << two << "' was not converted to true." << endl;
+ result += 1;
+ }
+ if (!(one <= two)) {
+ clog << "'" << one << " <= " << two << "' was not converted to true." << endl;
+ result += 1;
+ }
+ if (one > two) {
+ clog << "'" << one << " > " << two << "' was converted to true." << endl;
+ result += 1;
+ }
+ if (one >= two) {
+ clog << "'" << one << " >= " << two << "' was converted to true." << endl;
+ result += 1;
+ }
+
+ return result;
+}
+
+// These should fall back to looking up info flags.
+static unsigned exam_relational_possymbol()
+{
+ unsigned result = 0;
+ possymbol p("p");
+
+ if (p == 0) {
+ clog << "for positive p, 'p == 0' was converted to true." << endl;
+ result += 1;
+ }
+ if (!(p != 0)) {
+ clog << "for positive p, 'p != 0' was not converted to true." << endl;
+ result += 1;
+ }
+ if (p < 0) {
+ clog << "for positive p, 'p < 0' was converted to true." << endl;
+ result += 1;
+ }
+ if (p <= 0) {
+ clog << "for positive p, 'p <= 0' was converted to true." << endl;
+ result += 1;
+ }
+ if (!(p > 0)) {
+ clog << "for positive p, 'p > 0' was not converted to true." << endl;
+ result += 1;
+ }
+ if (!(p >= 0)) {
+ clog << "for positive p, 'p >= 0' was not converted to true." << endl;
+ result += 1;
+ }
+
+ return result;
+}
+
+// Very simple arithmetic should be supported, too.
+static unsigned exam_relational_arith()
+{
+ unsigned result = 0;
+ possymbol p("p");
+
+ if (!(p + 2 > p + 1)) {
+ clog << "for positive p, 'p + 2 > p + 1' was not converted to true." << endl;
+ result += 1;
+ }
+ if (!(p > -p)) {
+ clog << "for positive p, 'p > -p' was not converted to true." << endl;
+ result += 1;
+ }
+ if (!(2*p > p)) {
+ clog << "for positive p, '2*p > p' was not converted to true." << endl;
+ result += 1;
+ }
+
+ return result;
+}
+
+// Comparisons should maintain ordering invariants
+static unsigned exam_relational_order()
+{
+ unsigned result = 0;
+ numeric i = 1ll<<32, j = i+1;
+ symbol a;
+ relational x = i==a, y = j==a;
+ if (x.compare(y) != -y.compare(x)) {
+ clog << "comparison should be antisymmetric." << endl;
+ result += 1;
+ }
+
+ return result;
+}
+
+unsigned exam_relational()
+{
+ unsigned result = 0;
+
+ cout << "examining relational objects" << flush;
+
+ result += exam_relational_elementary(); cout << '.' << flush;
+ result += exam_relational_possymbol(); cout << '.' << flush;
+ result += exam_relational_arith(); cout << '.' << flush;
+ result += exam_relational_order(); cout << '.' << flush;
+
+ return result;
+}
+
+int main(int argc, char** argv)
+{
+ return exam_relational();
+}
--- /dev/null
+/** @file exam_sqrfree.cpp
+ *
+ */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ginac.h"
+using namespace GiNaC;
+
+#include <iostream>
+using namespace std;
+
+static unsigned exam_sqrfree1()
+{
+ unsigned result = 0;
+ symbol x("x");
+ ex e1, e2;
+
+ e1 = (1+x)*pow((2+x),2)*pow((3+x),3)*pow((4+x),4);
+ e2 = sqrfree(expand(e1), lst{x});
+ if (e1 != e2) {
+ clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+static unsigned exam_sqrfree2()
+{
+ unsigned result = 0;
+ symbol x("x"), y("y");
+ ex e1, e2;
+
+ e1 = (x+y)*pow((x+2*y),2)*pow((x+3*y),3)*pow((x+4*y),4);
+ e2 = sqrfree(expand(e1));
+ if (e1 != e2) {
+ clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+ e2 = sqrfree(expand(e1), lst{x});
+ if (e1 != e2) {
+ clog << "sqrfree(expand(" << e1 << "),[x]) erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+ e2 = sqrfree(expand(e1), lst{y});
+ if (e1 != e2) {
+ clog << "sqrfree(expand(" << e1 << "),[y]) erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+ e2 = sqrfree(expand(e1), lst{x,y});
+ if (e1 != e2) {
+ clog << "sqrfree(expand(" << e1 << "),[x,y]) erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+static unsigned exam_sqrfree3()
+{
+ unsigned result = 0;
+ symbol x("x"), y("y"), z("z");
+ ex e1, e2;
+
+ e1 = (x+y)*pow(x, 2)*(-z-1);
+ e2 = sqrfree(expand(e1));
+ if (!expand(e1 - e2).is_zero()) {
+ clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+
+ e1 = (x+y)*pow(x, 3)*(-z-1);
+ e2 = sqrfree(expand(e1));
+ if (!expand(e1 - e2).is_zero()) {
+ clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+// Bug in sqrfree_yun (fixed 2016-02-02).
+static unsigned exam_hidden_zero1()
+{
+ unsigned result = 0;
+ symbol x("x");
+ ex e;
+
+ e = (x-1)*(x+1) - x*x + 1; // an unexpanded 0...
+ try {
+ ex f = sqrfree(e);
+ if (!f.is_zero()) {
+ clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
+ ++result;
+ }
+ } catch (const exception &err) {
+ clog << "sqrfree(" << e << ") throws " << err.what() << endl;
+ ++result;
+ }
+
+ e = pow(x-1,3) - expand(pow(x-1,3)); // ...still after differentiating...
+ try {
+ ex f = sqrfree(e);
+ if (!f.is_zero()) {
+ clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
+ ++result;
+ }
+ } catch (const exception &err) {
+ clog << "sqrfree(" << e << ") throws " << err.what() << endl;
+ ++result;
+ }
+
+ e = pow(x-1,4) - expand(pow(x-1,4)); // ...and after differentiating twice.
+ try {
+ ex f = sqrfree(e);
+ if (!f.is_zero()) {
+ clog << "sqrfree(" << e << ") returns " << f << " instead of 0\n";
+ ++result;
+ }
+ } catch (const exception &err) {
+ clog << "sqrfree(" << e << ") throws " << err.what() << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+static unsigned exam_hidden_zero2()
+{
+ unsigned result = 0;
+ symbol x("x"), y("y");
+ ex e1, e2;
+
+ e1 = (1 + 3*x + 3*pow(x,2) + pow(x,3) - pow(1+x,3)) * y;
+ e2 = sqrfree(e1);
+ if (!e2.is_zero()) {
+ clog << "sqrfree(" << e1 << ") erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+
+ e1 = (pow(x,2)-2*x*y+pow(y,2)-pow(x-y,2)) * x;
+ e2 = sqrfree(e1);
+ if (!e2.is_zero()) {
+ clog << "sqrfree(" << e1 << ") erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+
+ e1 = (pow(x,2)-2*x*y+pow(y,2)-pow(x-y,2)) * (x+y);
+ e2 = sqrfree(e1);
+ if (!e2.is_zero()) {
+ clog << "sqrfree(" << e1 << ") erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+unsigned exam_sqrfree()
+{
+ unsigned result = 0;
+
+ cout << "examining square-free factorization" << flush;
+
+ result += exam_sqrfree1(); cout << '.' << flush;
+ result += exam_sqrfree2(); cout << '.' << flush;
+ result += exam_sqrfree3(); cout << '.' << flush;
+ result += exam_hidden_zero1(); cout << '.' << flush;
+ result += exam_hidden_zero2(); cout << '.' << flush;
+
+ return result;
+}
+
+unsigned exam_sqrfree_parfrac()
+{
+ symbol x("x");
+ // (expression, number of terms after partial fraction decomposition)
+ vector<pair<ex, unsigned>> exams = {
+ {ex("(x - 1) / (x^2*(x^2 + 2))", lst{x}), 3},
+ {ex("(1 - x^10) / x", lst{x}), 2},
+ {ex("(2*x^3 + x + 3) / ((x^2 + 1)^2)", lst{x}), 2},
+ {ex("1 / (x * (x+1)^2 * (x+2)^3)", lst{x}), 6},
+ {ex("(x*x + 3*x - 1) / (x^2*(x^2 + 2)^3)", lst{x}), 5},
+ {ex("(1 - x^10) / (x + 2)", lst{x}), 11},
+ {ex("(1 - x + 3*x^2) / (x^3 * (2+x)^2)", lst{x}), 5},
+ {ex("(1 - x) / (x^4 * (x - 2)^3)", lst{x}), 6},
+ {ex("(1 - 2*x + x^9) / (x^5 * (1 - x + x^2)^6)", lst{x}), 11}
+ };
+ unsigned result = 0;
+
+ cout << "\n"
+ << "examining square-free partial fraction decomposition" << flush;
+ for (auto e: exams) {
+ ex e1 = e.first;
+ ex e2 = sqrfree_parfrac(e1, x);
+ if (e2.nops() != e.second ||
+ !is_a<add>(e2) ||
+ !normal(e1-e2).is_zero()) {
+ clog << "sqrfree_parfrac(" << e1 << ", " << x << ") erroneously returned "
+ << e2 << endl;
+ ++result;
+ }
+ cout << '.' << flush;
+ }
+
+ return result;
+}
+
+int main(int argc, char** argv)
+{
+ unsigned result = 0;
+
+ result += exam_sqrfree();
+ result += exam_sqrfree_parfrac();
+
+ return result;
+}
* Small test for the structure<> template. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+++ /dev/null
-/**
- * @file factor_upoly_q_bug.cpp Check for a bug in factor_univariate().
- *
- * factor_univariate() didn't check if the argument is an integer polynomial,
- * the result was a segfault.
- */
-#include "ginac.h"
-#include <iostream>
-using namespace GiNaC;
-using namespace std;
-
-int main(int argc, char** argv)
-{
- cout << "checking if factor() handles rational polynomials. ";
- parser p;
- ex e = p("174247781*x^2-1989199947807987/200000000000000*x");
- ex ef = factor(e);
- ex diff = (e - ef).expand();
- cout << "yes" << endl;
- return 0;
-}
* input in the consistency checks. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+++ /dev/null
-/** @file mul_eval_memleak.cpp
- *
- * mul_eval_memleak.cpp Test for memory leak in {mul,power}::eval
- *
- * The bug was introduced by
- *
- * commit f418c6ee4d558c852e1fb95533af07a3ae43f409
- * Author: Alexei Sheplyakov <varg@theor.jinr.ru>
- * Date: Wed Jul 11 14:34:42 2007 +0400
- * (it was commited into the official branch as
- * commit a602d34c225dceb3e53742a7b3e19a4b5e280485
- * Author: Jens Vollinga <vollinga@thep.physik.uni-mainz.de>
- * Date: Wed Jul 11 21:07:40 2007 +0000)
- */
-
-/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <ginac/ginac.h>
-using namespace GiNaC;
-
-#include <iostream>
-#include <stdexcept>
-#include <string>
-using namespace std;
-
-const unsigned check_mul_eval_memleak(const unsigned N)
-{
- // Expanding this expression into a Laurent series triggers the bug.
- static const string e_str("\
-1/605927415293858601*tgamma(3-eps)^(-1)*tgamma(2-eps)*(5013234896802\
-*(-1+2*eps)*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log(920*scale\
-^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F)+(846400+2539001*eps\
-)*(2539001*(-1+2*eps)*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log\
-(920*scale^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F)+286523497\
-2800*(-1+eps)^(-1)*eps^(-2)*(920*scale^(-1))^(-2*eps)*(1301*scale^(-\
-1))^(-2*eps)*tgamma(1+eps)^2)+6061411748045832000*(-1+eps)^(-1)*eps^\
-(-2)*(920*scale^(-1))^(-2*eps)*(1301*scale^(-1))^(-2*eps)*tgamma(1+e\
-ps)^2+716056132401*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log(92\
-0*scale^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F))+71656139360\
-0/716056132401*tgamma(1-eps)*tgamma(2*eps)^(-1)*tgamma(eps)^2*tgamma\
-(3-eps)^(-1)*(920*scale^(-1))^(-4*eps)*tgamma(-1+2*eps)-2/6059274152\
-93858601*tgamma(3-eps)^(-1)*(2149010446400*(-1+2*eps)*((-2539001/2)*\
-eps^(-2)+(-7617003/2+1692800*log(920*scale^(-1))+3385202*log(1301*sc\
-ale^(-1)))*eps^(-1)+F)+2425134880977920000*(-1+eps)^(-1)*eps^(-2)*(9\
-20*scale^(-1))^(-2*eps)*(1301*scale^(-1))^(-2*eps)*tgamma(1+eps)^2-7\
-16056132401*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log(920*scale\
-^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F)+1692601*(-1+2*eps)*\
-(2539001*(-1+2*eps)*((-2539001/2)*eps^(-2)+(-7617003/2+1692800*log(9\
-20*scale^(-1))+3385202*log(1301*scale^(-1)))*eps^(-1)+F)+28652349728\
-00*(-1+eps)^(-1)*eps^(-2)*(920*scale^(-1))^(-2*eps)*(1301*scale^(-1)\
-)^(-2*eps)*tgamma(1+eps)^2))*tgamma(2-eps)+(1/716056132401*I)*tgamma\
-(-1+eps)*mb^2*(mb*scale^(-1))^(-2*eps)*((716392960000*I)*mb^(-2)*(92\
-0*scale^(-1))^(-2*eps)*tgamma(-2+eps)-(2864898145201*I)*mb^(-2)*(130\
-1*scale^(-1))^(-2*eps)*tgamma(-2+eps)-(716224526400*I)*tgamma(-1+eps\
-)*mb^(-2)*(920*scale^(-1))^(-2*eps))-3385202/605927415293858601*tgam\
-ma(3-eps)^(-1)*tgamma(2-eps)*(2539001*(-1+2*eps)*((-2539001/2)*eps^(\
--2)+(-7617003/2+1692800*log(920*scale^(-1))+3385202*log(1301*scale^(\
--1)))*eps^(-1)+F)+2865234972800*(-1+eps)^(-1)*eps^(-2)*(920*scale^(-\
-1))^(-2*eps)*(1301*scale^(-1))^(-2*eps)*tgamma(1+eps)^2+846201*((-25\
-39001/2)*eps^(-2)+(-7617003/2+1692800*log(920*scale^(-1))+3385202*lo\
-g(1301*scale^(-1)))*eps^(-1)+F))\
-");
- const symbol eps("eps"), scale("scale"), mb("mb"), F("F");
- const lst syms(eps, scale, mb, F);
- const ex e0(e_str, syms);
-
- unsigned i = 0;
- unsigned n_failures = 0;
-
- ex e;
- try {
- for (; i < N; i++)
- e = e0.series(eps, 1).subs(Euler==0).expand();
- } catch (std::bad_alloc) {
- return i;
- }
- return 0;
-}
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-static void set_VM_limit(const unsigned long MB) {
- const unsigned mem_lim_kb = MB*1024*1024;
- struct rlimit lim;
- lim.rlim_cur = mem_lim_kb;
- lim.rlim_max = mem_lim_kb;
- setrlimit(RLIMIT_AS, &lim);
-}
-
-int main(int argc, char** argv) {
- static const unsigned max_mem = 32; // megabytes
- // otherwise one need wait for a long[er] time.
- set_VM_limit(max_mem);
- static const unsigned n_of_tests = 10000;
- const unsigned n_loops = check_mul_eval_memleak(n_of_tests);
- if (n_loops) {
- cerr << "memory exhausted after " << n_loops << " loops" << endl;
- return 1;
- }
- return 0;
-}
+++ /dev/null
-/** @file numeric_archive.cpp
- *
- * Check for a bug in numeric::archive
- *
- * numeric::archive used to fail if the real part of a complex number
- * is a rational number and the imaginary part is a floating point one. */
-
-/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "ginac.h"
-using namespace GiNaC;
-
-#include <algorithm>
-#include <cln/cln.h>
-#include <iostream>
-#include <iterator>
-#include <sstream>
-#include <stdexcept>
-#include <vector>
-using namespace cln;
-
-struct archive_unarchive_check
-{
- cl_N operator()(const cl_N& n) const
- {
- ex e = numeric(n);
- archive ar;
- ar.archive_ex(e, "test");
- lst l;
- ex check = ar.unarchive_ex(l, "test");
- if (!check.is_equal(e)) {
- std::ostringstream s;
- s << __FILE__ << ':' << __LINE__ << ": expected: " << e << ", got " << check;
- throw std::logic_error(s.str());
- }
- return n;
- }
-};
-
-int main(int argc, char** argv)
-{
- const cl_I one(1);
- std::cout << "checking if numeric::archive handles complex numbers properly" << std::endl;
- const cl_R three_fp = cl_float(3.0, default_float_format);
- std::vector<cl_N> numbers;
- numbers.push_back(complex(one, three_fp));
- numbers.push_back(complex(three_fp, one));
- numbers.push_back(complex(three_fp, three_fp));
- numbers.push_back(complex(one, one));
- std::for_each(numbers.begin(), numbers.end(), archive_unarchive_check());
- return 0;
-}
+++ /dev/null
-/** @file parser_bugs.cpp
- *
- * Check for some silly bugs in the parser. */
-
-/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "ginac.h"
-using namespace GiNaC;
-
-#include <iostream>
-#include <sstream>
-#include <stdexcept>
-#include <string>
-
-// - a - b was misparsed as -a + b due to a bug in parser::parse_unary_expr()
-static int check1(std::ostream& err_str)
-{
- const std::string srep("-a-b");
- parser reader;
- ex e = reader(srep);
- ex a = reader.get_syms()["a"];
- ex b = reader.get_syms()["b"];
- ex g = - a - b;
- ex d = (e - g).expand();
- if (!d.is_zero()) {
- err_str << "\"" << srep << "\" was misparsed as \""
- << e << "\"" << std::endl;
- return 1;
- }
- return 0;
-}
-
-/// Parser was rejecting the valid expression '5 - (3*x)/10'.
-static int check2(std::ostream& err_str)
-{
- const std::string srep("5-(3*x)/10");
- parser reader;
- ex e = reader(srep);
- ex x = reader.get_syms()["x"];
- ex g = 5 - (3*x)/10;
- ex d = (e - g).expand();
- if (!d.is_zero()) {
- err_str << "\"" << srep << "\" was misparsed as \""
- << e << "\"" << std::endl;
- return 1;
- }
- return 0;
-}
-
-/// parse_literal_expr forget to consume the token, so parser get
-/// very confused.
-static int check3(std::ostream& err_str)
-{
- const std::string srep("5-(2*I)/3");
- parser reader;
- ex e = reader(srep);
- ex g = numeric(5) - (numeric(2)*I)/3;
- ex d = (e - g).expand();
- if (!d.is_zero()) {
- err_str << "\"" << srep << "\" was misparsed as \""
- << e << "\"" << std::endl;
- return 1;
- }
- return 0;
-}
-
-/// parser happily accepted various junk like 'x^2()+1'
-static int check4(std::ostream& err_str)
-{
- const std::string junk("x^2()+1");
- parser reader;
- ex e;
- try {
- e = reader(junk);
- err_str << "parser accepts junk: \"" << junk << "\"" << std::endl;
- return 1;
- } catch (parse_error& err) {
- // Ok, parser rejects the nonsense.
- return 0;
- }
-}
-
-int main(int argc, char** argv)
-{
- std::cout << "checking for parser bugs. " << std::flush;
- std::ostringstream err_str;
- int errors = 0;
- errors += check1(err_str);
- errors += check2(err_str);
- errors += check3(err_str);
- errors += check4(err_str);
- if (errors) {
- std::cout << "Yes, unfortunately:" << std::endl;
- std::cout << err_str.str();
- } else {
- std::cout << "Not found. ";
- }
- return errors;
-}
+++ /dev/null
-/** @file parser_memleak.cpp
- *
- * This small program exhibits the memory leak in the ginac_yylex().
- * Run it as
- *
- * valgrind --leak-check=yes ./parser_memleak
- *
- * or simply
- *
- * ulimit -v `expr 64 \* 1024` ./parser_memleak
- */
-
-/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <ginac/ginac.h>
-using namespace GiNaC;
-
-#include <iostream>
-#include <stdexcept>
-using namespace std;
-
-int main(int argc, char** argv) {
- const symbol x("x"), y("y");
- const lst syms(x, y);
- // parser-generated symbol => memory leak.
- static const char* str[] = { "x^2+2*x*y + cos(x)", "Li2(x/y) + log(y/x)" };
-
- // depends on the amount of the available VM, compiler options, etc.
- const unsigned N_max = 500000;
- unsigned N=0;
- ex e;
- try {
- for (; N < N_max; N++) {
- e = ex(str[N & 1], syms);
- }
- } catch (std::bad_alloc) {
- cerr << "N = " << N << endl;
- return 1;
- }
- return 0;
-}
+++ /dev/null
-#include <iostream>
-#include <string>
-#include "ginac.h"
-using namespace GiNaC;
-using namespace std;
-
-static const string srep("\
-792*z^8*w^4*x^3*y^4*u^7 + 24*z^4*w^4*x^2*y^3*u^4 \
-+ 264*z^8*w^3*x^2*y^7*u^5 + 198*z^4*w^5*x^5*y*u^6 \
-+ 110*z^2*w^3*x^5*y^4*u^6 - 120*z^8*w*x^4*u^6 \
-- 480*z^5*w*x^4*y^6*u^8 - 720*z^7*x^3*y^3*u^7 \
-+ 165*z^4*w^2*x^4*y*u^5 + 450*z^8*w^6*x^2*y*u^8 \
-+ 40*z^2*w^3*x^3*y^3*u^6 - 288*z^7*w^2*x^3*y^6*u^6 \
-+ 250*z^6*w^4*x^2*y^4*u^8 + 576*z^7*w^7*x^2*y^4*u^8 \
-- 80*z^6*w^2*x^5*y^3*u^7 - 144*z^8*w^4*x^5*u^7 \
-+ 120*z^4*w*x^2*y^6*u^6 + 320*z^5*w^5*x^2*y^7*u^8 \
-+ 192*z^7*w^6*x*y^7*u^6 - 12*z^4*w^3*x^3*y^5*u^6 \
-- 36*z^4*w^4*x^4*y^2*u^8 + 72*z^4*w^5*x^3*u^6 \
-- 20*z^2*w^2*x^4*y^5*u^8 + 660*z^8*w*x^2*y^4*u^6 \
-+ 66*z^4*w^4*x^4*y^4*u^4 + 440*z^6*w^2*x^3*y^7*u^7 \
-- 30*z^4*w*x^3*y^2*u^7 - 48*z^8*w^3*x^4*y^3*u^5 \
-+ 72*z^6*w^2*x*y^6*u^4 - 864*z^7*w^3*x^4*y^3*u^8 \
-+ 480*z^7*w^4*x*y^4*u^7 + 60*z^4*w^2*x^2*u^5 \
-+ 375*z^8*w^3*x*y*u^7 + 150*z^8*w^5*x*y^4*u^6 \
-+ 180*z^6*x*y^3*u^5 + 216*z^6*w^3*x^2*y^3*u^6");
-
-int main(int argc, char** argv)
-{
- cout << "Checking for more pgcd() bugs (infinite loop, miscalculation) ... " << flush;
- parser the_parser;
- ex e = the_parser(srep);
- const symbol x = ex_to<symbol>(the_parser.get_syms()["x"]);
- ex g = gcd(e, e.diff(x));
- ex should_be = the_parser(string("u^4*z^2"));
- if (!(g-should_be).expand().is_zero()) {
- cout << "GCD was miscomputed. " << flush;
- return 1;
- }
- cout << "not found. " << flush;
- return 0;
-}
+++ /dev/null
-/** @file pgcd_relatively_prime_bug.cpp
- *
- * A program exposing historical bug in the pgcd() function.
- */
-#include <string>
-#include <iostream>
-#include <utility>
-#include "ginac.h"
-using namespace std;
-using namespace GiNaC;
-
-int main(int argc, char** argv)
-{
- cout << "Checking for pgcd() bug regarding relatively prime polynomials: " << flush;
- const symbol q("q");
- parser reader;
- reader.get_syms().insert(make_pair(string("q"), q));
-
- ex t = reader("-E20^16*E4^8*E5^8*E1^16*q^4"
- "-(E10^24-E20^8*E5^16)*E4^16*E1^8"
- "+E2^24*E20^16*E5^8*q^4");
- ex g = gcd(t.expand(), t.diff(q).expand()) - 1;
- if (!g.is_zero()) {
- cout << " oops!" << endl <<
- "** Error: should be 0, got " << g << endl << flush;
- throw std::logic_error("gcd was miscalculated");
- }
- cout << "not found" << endl << flush;
- return 0;
-}
-
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Utility functions for benchmarking. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* This program is based on work by
* Isabella Bierenbaum <bierenbaum@thep.physik.uni-mainz.de> and
* Dirk Kreimer <dkreimer@bu.edu>.
- * For details, please see <http://www.arXiv.org/abs/hep-th/0111192>.
+ * For details, please see <https://www.arXiv.org/abs/hep-th/0111192>.
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
return typeid(*vert).before(typeid(*n.vert));
// Are the indices of the top-level nodes different?
if (!(*vert==*n.vert))
- return (vert<n.vert);
+ return (*vert<*n.vert);
// Are the sets of children different, one by one?
return (children<n.children);
}
* after which e should be just a1^2. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Some timings on series expansion of the Gamma function around a pole. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* by Robert H. Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Fermat-test). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Lewis and Michael Wester. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Time the parser. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Time the different GCD algorithms. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* A simple stop watch class. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* A simple stop watch class. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- /dev/null
+get_filename_component(ginac_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+include(CMakeFindDependencyMacro)
+find_package(CLN 1.2.2 REQUIRED)
+
+if (NOT TARGET ginac::ginac)
+ include("${ginac_CMAKE_DIR}/ginac-targets.cmake")
+endif()
+
+set(ginac_LIBRARIES ginac::ginac)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CLN REQUIRED_VARS CLN_LIBRARIES CLN_INCLUDE_DIR
VERSION_VAR CLN_VERSION)
+if (CLN_FOUND AND NOT TARGET cln::cln)
+ set(_found_shared_libcln FALSE)
+ get_filename_component(_libcln_suffix ${CLN_LIBRARIES} EXT)
+ if (_libcln_suffix STREQUAL ${CMAKE_STATIC_LIBRARY_SUFFIX})
+ # XXX: msvc uses the same suffix for both static and import libraries
+ add_library(cln::cln STATIC IMPORTED)
+ else()
+ set(_found_shared_libcln TRUE)
+ add_library(cln::cln SHARED IMPORTED)
+ endif()
+ set_target_properties(cln::cln PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES ${CLN_INCLUDE_DIR}
+ )
+ if (WIN32 AND _found_shared_libcln)
+ set_target_properties(cln::cln PROPERTIES
+ IMPORTED_IMPLIB ${CLN_LIBRARIES}
+ )
+ else()
+ set_target_properties(cln::cln PROPERTIES
+ IMPORTED_LOCATION ${CLN_LIBRARIES}
+ )
+ endif()
+endif()
--- /dev/null
+compile
+config.guess
+config.h
+config.h.in
+config.sub
+depcomp
+install-sh
+ltmain.sh
+mdate-sh
+missing
+stamp-h1
+test-driver
+texinfo.tex
+ylwrap
# Output a system dependent set of variables, describing how to set the
# run time search path of shared libraries in an executable.
#
-# Copyright 1996-2015 Free Software Foundation, Inc.
+# Copyright 1996-2023 Free Software Foundation, Inc.
# Taken from GNU libtool, 2001
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
#
hardcode_direct=yes
hardcode_minus_L=yes
;;
- freebsd* | dragonfly*)
+ freebsd* | dragonfly* | midnightbsd*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
freebsd[23].*)
library_names_spec='$libname$shrext$versuffix'
;;
- freebsd* | dragonfly*)
+ freebsd* | dragonfly* | midnightbsd*)
library_names_spec='$libname$shrext'
;;
gnu*)
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])
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],
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])
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
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"],
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)
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}
add_custom_command(
OUTPUT ${_ind}
COMMAND ${MAKEINDEX_COMPILER} ${_idx}
- COMMAND python ${_fixupind} ${_idx}
WORKING_DIRECTORY ${_dirname}
DEPENDS ${texfile} ${_idx}
COMMENT "MAKEINDEX ${_basename}.idx")
--- /dev/null
+*.html
+*.info
+*.txt
-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)
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
*/
#include <fstream>
-using namespace std;
+
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
#include <ginac/ginac.h>
+#endif
+using namespace std;
using namespace GiNaC;
int main()
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");
#include <ctime>
#include <iostream>
-using namespace std;
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
#include <ginac/ginac.h>
+#endif
+using namespace std;
using namespace GiNaC;
/*
// First using compile_ex
{
- double result;
+ double result = 0.0;
double point = 0.2;
start = clock();
for (int i=0; i<100000; ++i) {
// Then without compile_ex
{
- ex result;
+ ex result = 0.0;
ex point = 0.2;
start = clock();
for (int i=0; i<100000; ++i) {
#include <iostream>
-using namespace std;
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
#include <ginac/ginac.h>
-using namespace GiNaC;
+#endif
// Yes, we are using CUBA (should be installed on the system!)
#include <cuba.h>
+using namespace std;
+using namespace GiNaC;
+
/*
* Demonstrates the use of compile_ex with the CUBA library.
*
#include <ctime>
#include <iostream>
-using namespace std;
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
#include <ginac/ginac.h>
+#endif
+using namespace std;
using namespace GiNaC;
/*
#include <iostream>
#include <string>
#include <stdexcept>
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
#include <ginac/ginac.h>
+#endif
using namespace std;
using namespace GiNaC;
* 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
*
* MA 02110-1301 USA
*/
+#include <getopt.h>
#include <vector>
#include <cstddef> // for size_t
#include <iostream>
#include <iostream>
#include <string>
#include <stdexcept>
-using namespace std;
-
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
#include <ginac/ginac.h>
+#endif
+using namespace std;
using namespace GiNaC;
class mystring : public basic
GINAC_DECLARE_REGISTERED_CLASS(mystring, basic)
public:
mystring(const string &s);
- ex eval(int level) const override;
+ ex eval() const override;
private:
string str;
* evaluation: all strings automatically converted to lowercase with
* non-alphabetic characters stripped, and empty strings removed
*/
-ex mystring::eval(int level) const
+ex mystring::eval() const
{
string new_str;
for (size_t i=0; i<str.length(); i++) {
--- /dev/null
+Doxy*
+Doxy*!.in!
<hr>
<small><i>This page is part of the <b><a
-href="http://www.ginac.de/">GiNaC</a></b>
+href="https://www.ginac.de/">GiNaC</a></b>
developer's reference. It was generated automatically by <a
-href="http://www.stack.nl/~dimitri/doxygen/index.html">doxygen</a>. For
+href="https://www.doxygen.nl/">doxygen</a>. For
an introduction, see the <a href="../tutorial/">tutorial</a>.</i></small>
</body>
</html>
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
--- /dev/null
+*.info
+stamp-vti
+version.texi
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-2023 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
@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-2023 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
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
@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-2023 Johannes Gutenberg
University Mainz, Germany.
This program is free software; you can redistribute it and/or
@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;
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);
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
-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:
@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.
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
method, where the left hand side of the relation specifies the variable
to expand in and the right hand side the expansion point. They can also
be used for creating systems of equations that are to be solved for
-unknown variables. But the most common usage of objects of this class
+unknown variables.
+
+But the most common usage of objects of this class
is rather inconspicuous in statements of the form @code{if
(expand(pow(a+b,2))==a*a+2*a*b+b*b) @{...@}}. Here, an implicit
conversion from @code{relational} to @code{bool} takes place. Note,
however, that @code{==} here does not perform any simplifications, hence
@code{expand()} must be called explicitly.
+Simplifications of
+relationals may be more efficient if preceded by a call to
+@example
+ex relational::canonical() const
+@end example
+which returns an equivalent relation with the zero
+right-hand side. For example:
+@example
+possymbol p("p");
+relational rel = (p >= (p*p-1)/p);
+if (ex_to<relational>(rel.canonical().normal()))
+ cout << "correct inequality" << endl;
+@end example
+However, a user shall not expect that any inequality can be fully
+resolved by GiNaC.
+
@node Integrals, Matrices, Relations, Basic concepts
@c node-name, next, previous, up
@section Integrals
* 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.
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
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
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;
@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()}
@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()}
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
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
@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
@example
#include <fstream>
-using namespace std;
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
@example
#include <iostream>
-using namespace std;
-
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
struct sprod_s @{
#include <iostream>
#include <string>
#include <stdexcept>
-using namespace std;
-
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
@end example
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
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
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
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}
--- /dev/null
+.libs/
+function.h
+function.cpp
+.Tpo
-cmake_minimum_required(VERSION 2.6)
set(ginaclib_sources
add.cpp
inifcns.cpp
inifcns_gamma.cpp
inifcns_nstdsums.cpp
+ inifcns_elliptic.cpp
inifcns_trans.cpp
+ integration_kernel.cpp
integral.cpp
lst.cpp
matrix.cpp
indexed.h
inifcns.h
integral.h
+ integration_kernel.h
lst.h
matrix.h
mul.h
utils.h
crc32.h
hash_seed.h
+ utils_multi_iterator.h
parser/lexer.h
parser/debug.h
polynomial/gcd_euclid.h
)
add_library(ginac ${ginaclib_sources})
-add_definitions(-DLIBEXECDIR="${LIBEXECDIR}/")
+add_library(ginac::ginac ALIAS ginac)
set_target_properties(ginac PROPERTIES
SOVERSION ${ginaclib_soversion}
VERSION ${ginaclib_version})
-target_link_libraries(ginac ${CLN_LIBRARIES})
-include_directories(${CMAKE_SOURCE_DIR}/ginac)
+target_compile_definitions(ginac
+ PUBLIC $<BUILD_INTERFACE:IN_GINAC>
+ PRIVATE -DLIBEXECDIR="${LIBEXECDIR}/" HAVE_CONFIG_H
+)
+target_link_libraries(ginac PUBLIC cln::cln ${LIBDL_LIBRARIES})
+target_include_directories(ginac PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/..>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+if (WIN32 AND CMAKE_COMPILER_IS_GNUCXX AND BUILD_SHARED_LIBS)
+ set_target_properties(ginac PROPERTIES
+ LINK_FLAGS "-Wl,--enable-auto-import -Wl,--export-all-symbols"
+ )
+endif()
if (NOT BUILD_SHARED_LIBS)
set_target_properties(ginac PROPERTIES OUTPUT_NAME "ginac")
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)
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 \
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 \
* Implementation of GiNaC's sums of expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's sums of expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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;
* Archiving of GiNaC expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "registrar.h"
#include "ex.h"
#include "lst.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
#include "version.h"
#include <iostream>
/** 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). */
* Archiving of GiNaC expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Assertion macro definition. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's ABC. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's ABC. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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;
* Helper templates to provide per-class information for class hierarchies. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's clifford algebra (Dirac gamma) objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
ev.reserve(e1.nops());
cv.reserve(e1.nops());
// separate clifford and non-clifford entries
- for (int i= 0; i < e1.nops(); ++i) {
+ for (size_t i= 0; i < e1.nops(); ++i) {
if (is_a<clifford>(e1.op(i)) && is_a<cliffordunit>(e1.op(i).op(0)))
cv.push_back(e1.op(i));
else
bool found=false, same_value_found=false;
ex dummy_ind=0;
ev.reserve(e1.nops());
- for (int i=0; i < e1.nops();++i) {
+ for (size_t i=0; i < e1.nops(); ++i) {
// look for a Clifford unit with the same metric and representation label,
// if found remember its index
if (is_a<clifford>(e1.op(i)) && ex_to<clifford>(e1.op(i)).get_representation_label() == rl
* Interface to GiNaC's clifford algebra (Dirac gamma) objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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. */
* @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
* Implementation of GiNaC's color (SU(3) Lie algebra) objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's color (SU(3) Lie algebra) objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Definition of optimizing macros. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's constant types and some special constants. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's constant types and some special constants. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Wrapper template for making GiNaC classes out of STL containers. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
inline void container_storage<std::vector>::reserve(std::vector<ex> & v, size_t n) { v.reserve(n); }
-/** Helper template to allow initialization of containers via an overloaded
- * comma operator (idea stolen from Blitz++). */
-template <typename T, typename STLT>
-class container_init {
-public:
- container_init(STLT & s) : stlt(s) {}
-
- container_init<T, STLT> operator,(const T & x)
- {
- stlt.push_back(x);
- return container_init<T, STLT>(stlt);
- }
-
- // The following specializations produce much tighter code than the
- // general case above
-
- container_init<T, STLT> operator,(int x)
- {
- stlt.push_back(x);
- return container_init<T, STLT>(stlt);
- }
-
- container_init<T, STLT> operator,(unsigned int x)
- {
- stlt.push_back(x);
- return container_init<T, STLT>(stlt);
- }
-
- container_init<T, STLT> operator,(long x)
- {
- stlt.push_back(x);
- return container_init<T, STLT>(stlt);
- }
-
- container_init<T, STLT> operator,(unsigned long x)
- {
- stlt.push_back(x);
- return container_init<T, STLT>(stlt);
- }
-
- container_init<T, STLT> operator,(double x)
- {
- stlt.push_back(x);
- return container_init<T, STLT>(stlt);
- }
-
- container_init<T, STLT> operator,(const symbol & x)
- {
- stlt.push_back(T(x));
- return container_init<T, STLT>(stlt);
- }
-
-private:
- container_init();
- STLT & stlt;
-};
-
/** Wrapper template for making GiNaC classes out of STL containers. */
template <template <class T, class = std::allocator<T>> class C>
class container : public basic, public container_storage<C> {
setflag(get_default_flags());
}
- explicit container(const ex & p1) attribute_deprecated;
- container(const ex & p1, const ex & p2) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15) attribute_deprecated;
- container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15, const ex & p16) attribute_deprecated;
-
- // First step of initialization of container with a comma-separated
- // sequence of expressions. Subsequent steps are handled by
- // container_init<>::operator,().
- container_init<ex, STLT> operator=(const ex & x) attribute_deprecated;
-
// functions overriding virtual functions from base classes
public:
bool info(unsigned inf) const override { return inherited::info(inf); }
setflag(get_default_flags());
}
-/** Deprecatd constructors (prefer initializer list) */
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1)
- : container_storage<C>(1, p1) { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2)
- : container_storage<C>{p1, p2} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3)
- : container_storage<C>{p1, p2, p3} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4)
- : container_storage<C>{p1, p2, p3, p4} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5)
- : container_storage<C>{p1, p2, p3, p4, p5} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6)
- : container_storage<C>{p1, p2, p3, p4, p5, p6} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15} { setflag(get_default_flags()); }
-template <template <class T, class = std::allocator<T>> class C>
-container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
- const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15, const ex & p16)
- : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16} { setflag(get_default_flags()); }
-
-template <template <class T, class = std::allocator<T>> class C>
-container_init<ex, typename container_storage<C>::STLT> container<C>::operator=(const ex & x)
-{
- this->seq.push_back(x);
- return container_init<ex, typename container_storage<C>::STLT>(this->seq);
-}
-
template <template <class T, class = std::allocator<T>> class C>
void container<C>::do_print(const print_context & c, unsigned level) const
{
* Implementation of GiNaC's light-weight expression handles. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
bp->dbgprinttree();
}
+/** Expand an expression.
+ * @param options see GiNaC::expand_options */
ex ex::expand(unsigned options) const
{
if (options == 0 && (bp->flags & status_flags::expanded)) // The "expanded" flag only covers the standard options; someone might want to re-expand with different options
* Interface to GiNaC's light-weight expression handles. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* of this class in every object file that makes use of our flyweights in
* order to guarantee proper initialization. Hence we put it into this
* file which is included by every relevant file anyways. This is modeled
- * after section 27.4.2.1.6 of the C++ standard, where cout and friends are
+ * after section [ios::Init] of the C++ standard, where cout and friends are
* set up.
*
* @see utils.cpp */
// operand access
size_t nops() const { return bp->nops(); }
ex op(size_t i) const { return bp->op(i); }
- ex operator[](const ex & index) const { return (*bp)[index]; }
- ex operator[](size_t i) const { return (*bp)[i]; }
+ ex operator[](const ex & index) const { return (const_cast<const basic&>(*bp))[index]; }
+ ex operator[](size_t i) const { return (const_cast<const basic&>(*bp))[i]; }
ex & let_op(size_t i);
ex & operator[](const ex & index);
ex & operator[](size_t i);
// Iterators
-class const_iterator : public std::iterator<std::random_access_iterator_tag, ex, ptrdiff_t, const ex *, const ex &> {
+class const_iterator {
friend class ex;
friend class const_preorder_iterator;
friend class const_postorder_iterator;
-
public:
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = ex;
+ using difference_type = ptrdiff_t;
+ using pointer = const ex *;
+ using reference = const ex &;
+
const_iterator() noexcept {}
private:
} // namespace internal
-class const_preorder_iterator : public std::iterator<std::forward_iterator_tag, ex, ptrdiff_t, const ex *, const ex &> {
+class const_preorder_iterator {
public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = ex;
+ using difference_type = ptrdiff_t;
+ using pointer = const ex *;
+ using reference = const ex &;
const_preorder_iterator() noexcept {}
const_preorder_iterator(const ex &e, size_t n)
}
};
-class const_postorder_iterator : public std::iterator<std::forward_iterator_tag, ex, ptrdiff_t, const ex *, const ex &> {
+class const_postorder_iterator {
public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = ex;
+ using difference_type = ptrdiff_t;
+ using pointer = const ex *;
+ using reference = const ex &;
const_postorder_iterator() noexcept {}
const_postorder_iterator(const ex &e, size_t n)
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* fast numerical integration. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* C code equivalent in double precision. The function pointer has type FUNCP_2P.
*
* @param expr Expression to be compiled
- * @param sym Symbol from the expression to become the function parameter
+ * @param sym1 Symbol from the expression to become the first function parameter
+ * @param sym2 Symbol from the expression to become the second function parameter
* @param fp Returned function pointer
* @param filename Name of the intermediate source code and so-file. If
* supplied, these intermediate files will not be deleted
* Takes an expression and produces a function pointer to the compiled and linked
* C code equivalent in double precision. The function pointer has type FUNCP_CUBA.
*
- * @param expr Expression to be compiled
- * @param sym Symbol from the expression to become the function parameter
+ * @param exprs List of expression to be compiled
+ * @param syms Symbols from the expression to become the function parameters
* @param fp Returned function pointer
* @param filename Name of the intermediate source code and so-file. If
* supplied, these intermediate files will not be deleted
* Implementation of expression pairs (building blocks of expairseq). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Definition of expression pairs (building blocks of expairseq). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of sequences of expression pairs. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to sequences of expression pairs. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's exprseq. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Definition of GiNaC's exprseq. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
typedef container<std::vector> exprseq;
+/** Declaration of container::reg_info for exprseq. */
+#ifndef _MSC_VER // workaround error C2766: explicit specialization; 'reg_info' has already been defined
+template<> registered_class_info exprseq::reg_info;
+#endif
+
// defined in exprseq.cpp
template<> bool exprseq::info(unsigned inf) const;
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "normal.h"
#include "add.h"
+#include <type_traits>
#include <algorithm>
#include <limits>
#include <list>
namespace GiNaC {
+// anonymous namespace to hide all utility functions
+namespace {
+
#ifdef DEBUGFACTOR
#define DCOUT(str) cout << #str << endl
#define DCOUTVAR(var) cout << #var << ": " << var << endl
#define DCOUT2(str,var)
#endif // def DEBUGFACTOR
-// anonymous namespace to hide all utility functions
-namespace {
-
////////////////////////////////////////////////////////////////////////////////
// modular univariate polynomial code
typedef std::vector<cln::cl_I> upoly;
typedef vector<umodpoly> upvec;
-// COPY FROM UPOLY.HPP
+
+// COPY FROM UPOLY.H
// CHANGED size_t -> int !!!
template<typename T> static int degree(const T& p)
return p[p.size() - 1];
}
+/** Make the polynomial unit normal (having unit normal leading coefficient).
+ *
+ * @param[in, out] a polynomial to make unit normal
+ * @return true if polynomial a was already unit normal, false otherwise
+ */
static bool normalize_in_field(umodpoly& a)
{
if (a.size() == 0)
return false;
}
+/** Remove leading zero coefficients from polynomial.
+ *
+ * @param[in, out] p polynomial from which the zero leading coefficients will be removed
+ * @param[in] hint assume all coefficients of order ≥ hint are zero
+ */
template<typename T> static void
canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
{
- if (p.empty())
- return;
+ std::size_t i = min(p.size(), hint);
- std::size_t i = p.size() - 1;
- // Be fast if the polynomial is already canonicalized
- if (!zerop(p[i]))
- return;
-
- if (hint < p.size())
- i = hint;
+ while ( i-- && zerop(p[i]) ) { }
- bool is_zero = false;
- do {
- if (!zerop(p[i])) {
- ++i;
- break;
- }
- if (i == 0) {
- is_zero = true;
- break;
- }
- --i;
- } while (true);
-
- if (is_zero) {
- p.clear();
- return;
- }
-
- p.erase(p.begin() + i, p.end());
+ p.erase(p.begin() + i + 1, p.end());
}
-// END COPY FROM UPOLY.HPP
-
-static void expt_pos(umodpoly& a, unsigned int q)
-{
- if ( a.empty() ) return;
- cl_MI zero = a[0].ring()->zero();
- int deg = degree(a);
- a.resize(degree(a)*q+1, zero);
- for ( int i=deg; i>0; --i ) {
- a[i*q] = a[i];
- a[i] = zero;
- }
-}
-
-template<bool COND, typename T = void> struct enable_if
-{
- typedef T type;
-};
-
-template<typename T> struct enable_if<false, T> { /* empty */ };
+// END COPY FROM UPOLY.H
template<typename T> struct uvar_poly_p
{
return e;
}
-/** Divides all coefficients of the polynomial a by the integer x.
+/** Divides all coefficients of the polynomial a by the positive integer x.
* All coefficients are supposed to be divisible by x. If they are not, the
- * the<cl_I> cast will raise an exception.
+ * division will raise an exception.
*
* @param[in,out] a polynomial of which the coefficients will be reduced by x
- * @param[in] x integer that divides the coefficients
+ * @param[in] x positive integer that divides the coefficients
*/
static void reduce_coeff(umodpoly& a, const cl_I& x)
{
for (auto & i : a) {
// cln cannot perform this division in the modular field
cl_I c = R->retract(i);
- i = cl_MI(R, the<cl_I>(c / x));
+ i = cl_MI(R, exquopos(c, x));
}
}
} while ( k-- );
fill(r.begin()+n, r.end(), a[0].ring()->zero());
- canonicalize(r);
+ canonicalize(r, n);
}
/** Calculates quotient of a/b.
static bool unequal_one(const umodpoly& a)
{
- if ( a.empty() ) return true;
return ( a.size() != 1 || a[0] != a[0].ring()->one() );
}
return equal_one(c);
}
+/** Computes w^q mod a.
+ * Uses theorem 2.1 from A.K.Lenstra's PhD thesis; see exercise 8.13 in [GCL].
+ *
+ * @param[in] w polynomial
+ * @param[in] a modulus polynomial
+ * @param[in] q common modulus of w and a
+ * @param[out] r result
+ */
+static void expt_pos_Q(const umodpoly& w, const umodpoly& a, unsigned int q, umodpoly& r)
+{
+ if ( w.empty() ) return;
+ cl_MI zero = w[0].ring()->zero();
+ int deg = degree(w);
+ umodpoly buf(deg*q+1, zero);
+ for ( size_t i=0; i<=deg; ++i ) {
+ buf[i*q] = w[i];
+ }
+ rem(buf, a, r);
+}
+
// END modular univariate polynomial code
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/** Calculates the Q matrix for a polynomial. Used by Berlekamp's algorithm.
+ *
+ * The implementation follows algorithm 8.5 of [GCL].
*
* @param[in] a_ modular polynomial
* @param[out] Q Q matrix
/** Berlekamp's modular factorization.
*
- * The implementation follows the algorithm in chapter 8 of [GCL].
+ * The implementation follows algorithm 8.4 of [GCL].
*
* @param[in] a modular polynomial
* @param[out] upv vector containing modular factors. if upv was not empty the
/** Calculates a^(1/prime).
*
- * @param[in] a polynomial
- * @param[in] prime prime number -> exponent 1/prime
- * @param[in] ap resulting polynomial
+ * @param[in] a polynomial
+ * @param[in] prime prime number -> exponent 1/prime
+ * @param[out] ap resulting polynomial
*/
static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap)
{
/** Distinct degree factorization (DDF).
*
- * The implementation follows the algorithm in chapter 8 of [GCL].
+ * The implementation follows algorithm 8.8 of [GCL].
*
* @param[in] a_ modular polynomial
* @param[out] degrees vector containing the degrees of the factors of the
int nhalf = degree(a)/2;
int i = 1;
- umodpoly w(2);
- w[0] = R->zero();
- w[1] = R->one();
+ umodpoly w = {R->zero(), R->one()};
umodpoly x = w;
while ( i <= nhalf ) {
- expt_pos(w, q);
umodpoly buf;
- rem(w, a, buf);
+ expt_pos_Q(w, a, q, buf);
w = buf;
- umodpoly wx = w - x;
- gcd(a, wx, buf);
+ gcd(a, w - x, buf);
if ( unequal_one(buf) ) {
degrees.push_back(i);
ddfactors.push_back(buf);
- }
- if ( unequal_one(buf) ) {
umodpoly buf2;
div(a, buf, buf2);
a = buf2;
return r;
}
-/** Calculates the bound for the modulus.
- * See [Mig].
+/** Calculates bound for the product of absolute values (modulus) of the roots.
+ * Uses Landau's inequality, see [Mig].
*/
-static inline cl_I calc_bound(const ex& a, const ex& x, int maxdeg)
+static inline cl_I calc_bound(const ex& a, const ex& x)
{
- cl_I maxcoeff = 0;
- cl_R coeff = 0;
+ cl_R radicand = 0;
for ( int i=a.degree(x); i>=a.ldegree(x); --i ) {
cl_I aa = abs(the<cl_I>(ex_to<numeric>(a.coeff(x, i)).to_cl_N()));
- if ( aa > maxcoeff ) maxcoeff = aa;
- coeff = coeff + square(aa);
+ radicand = radicand + square(aa);
}
- cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff)));
- cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg));
- return ( B > maxcoeff ) ? B : maxcoeff;
+ return ceiling1(the<cl_R>(cln::sqrt(radicand)));
}
-/** Calculates the bound for the modulus.
- * See [Mig].
+/** Calculates bound for the product of absolute values (modulus) of the roots.
+ * Uses Landau's inequality, see [Mig].
*/
-static inline cl_I calc_bound(const upoly& a, int maxdeg)
+static inline cl_I calc_bound(const upoly& a)
{
- cl_I maxcoeff = 0;
- cl_R coeff = 0;
+ cl_R radicand = 0;
for ( int i=degree(a); i>=0; --i ) {
cl_I aa = abs(a[i]);
- if ( aa > maxcoeff ) maxcoeff = aa;
- coeff = coeff + square(aa);
+ radicand = radicand + square(aa);
}
- cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff)));
- cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg));
- return ( B > maxcoeff ) ? B : maxcoeff;
+ return ceiling1(the<cl_R>(cln::sqrt(radicand)));
}
/** Hensel lifting as used by factor_univariate().
*
- * The implementation follows the algorithm in chapter 6 of [GCL].
+ * The implementation follows algorithm 6.1 of [GCL].
*
* @param[in] a_ primitive univariate polynomials
* @param[in] p prime number that does not divide lcoeff(a)
// calc bound B
int maxdeg = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
- cl_I maxmodulus = 2*calc_bound(a, maxdeg);
+ cl_I maxmodulus = ash(calc_bound(a), maxdeg+1); // = 2 * calc_bound(a) * 2^maxdeg
// step 1
cl_I alpha = lcoeff(a);
}
}
-/** Returns a new prime number.
+/** Returns a new small prime number.
*
- * @param[in] p prime number
- * @return next prime number after p
+ * @param[in] n an integer
+ * @return smallest prime greater than n
*/
-static unsigned int next_prime(unsigned int p)
-{
- static vector<unsigned int> primes;
- if (primes.empty()) {
- primes = {3, 5, 7};
- }
- if ( p >= primes.back() ) {
- unsigned int candidate = primes.back() + 2;
- while ( true ) {
- size_t n = primes.size()/2;
- for ( size_t i=0; i<n; ++i ) {
- if (candidate % primes[i])
- continue;
- candidate += 2;
- i=-1;
- }
- primes.push_back(candidate);
- if (candidate > p)
+static unsigned int next_prime(unsigned int n)
+{
+ static vector<unsigned int> primes = {2, 3, 5, 7};
+ unsigned int candidate = primes.back();
+ while (primes.back() <= n) {
+ candidate += 2;
+ bool is_prime = true;
+ for (size_t i=1; primes[i]*primes[i]<=candidate; ++i) {
+ if (candidate % primes[i] == 0) {
+ is_prime = false;
break;
+ }
}
- return candidate;
+ if (is_prime)
+ primes.push_back(candidate);
}
for (auto & it : primes) {
- if ( it > p ) {
+ if ( it > n ) {
return it;
}
}
throw logic_error("next_prime: should not reach this point!");
}
-/** Manages the splitting a vector of of modular factors into two partitions.
+/** Manages the splitting of a vector of modular factors into two partitions.
*/
class factor_partition
{
poly.unitcontprim(x, unit, cont, prim_ex);
upoly prim;
upoly_from_ex(prim, prim_ex, x);
+ if (prim_ex.is_equal(1)) {
+ return poly;
+ }
// determine proper prime and minimize number of modular factors
prime = 3;
* with deg(s_i) < deg(a_i)
* and with given b_1 = a_1 * ... * a_{i-1} * a_{i+1} * ... * a_r
*
- * The implementation follows the algorithm in chapter 6 of [GCL].
+ * The implementation follows algorithm 6.3 of [GCL].
*
* @param[in] a vector of modular univariate polynomials
* @param[in] x symbol
*
* Solves s*a + t*b == 1 mod p^k given a,b.
*
- * The implementation follows the algorithm in chapter 6 of [GCL].
+ * The implementation follows algorithm 6.3 of [GCL].
*
* @param[in] a polynomial
* @param[in] b polynomial
* s_1*b_1 + ... + s_r*b_r == x^m mod p^k
* with given b_1 = a_1 * ... * a_{i-1} * a_{i+1} * ... * a_r
*
- * The implementation follows the algorithm in chapter 6 of [GCL].
+ * The implementation follows algorithm 6.3 of [GCL].
*
* @param a vector with univariate polynomials mod p^k
* @param x symbol
* s_1*b_1 + ... + s_r*b_r == c mod <I^(d+1),p^k>
* with given b_1 = a_1 * ... * a_{i-1} * a_{i+1} * ... * a_r
*
- * The implementation follows the algorithm in chapter 6 of [GCL].
+ * The implementation follows algorithm 6.2 of [GCL].
*
* @param a_ vector of multivariate factors mod p^k
* @param x symbol (equiv. x_1 in [GCL])
}
/** Multivariate Hensel lifting.
- * The implementation follows the algorithm in chapter 6 of [GCL].
+ * The implementation follows algorithm 6.4 of [GCL].
* Since we don't have a data type for modular multivariate polynomials, the
* respective operations are done in a GiNaC::ex and the function
* make_modular() is then called to make the coefficient modular p^l.
}
}
-/** Takes a factorized expression and puts the factors in a lst. The exponents
+/** Takes a factorized expression and puts the factors in a vector. The exponents
* of the factors are discarded, e.g. 7*x^2*(y+1)^4 --> {7,x,y+1}. The first
- * element of the list is always the numeric coefficient.
+ * element of the result is always the numeric coefficient.
*/
-static ex put_factors_into_lst(const ex& e)
+static exvector put_factors_into_vec(const ex& e)
{
- lst result;
+ exvector result;
if ( is_a<numeric>(e) ) {
- result.append(e);
+ result.push_back(e);
return result;
}
if ( is_a<power>(e) ) {
- result.append(1);
- result.append(e.op(0));
+ result.push_back(1);
+ result.push_back(e.op(0));
return result;
}
if ( is_a<symbol>(e) || is_a<add>(e) ) {
ex icont(e.integer_content());
- result.append(icont);
- result.append(e/icont);
+ result.push_back(icont);
+ result.push_back(e/icont);
return result;
}
if ( is_a<mul>(e) ) {
ex nfac = 1;
+ result.push_back(nfac);
for ( size_t i=0; i<e.nops(); ++i ) {
ex op = e.op(i);
if ( is_a<numeric>(op) ) {
nfac = op;
}
if ( is_a<power>(op) ) {
- result.append(op.op(0));
+ result.push_back(op.op(0));
}
if ( is_a<symbol>(op) || is_a<add>(op) ) {
- result.append(op);
+ result.push_back(op);
}
}
- result.prepend(nfac);
+ result[0] = nfac;
return result;
}
- throw runtime_error("put_factors_into_lst: bad term.");
+ throw runtime_error("put_factors_into_vec: bad term.");
}
/** Checks a set of numbers for whether each number has a unique prime factor.
*
- * @param[in] f list of numbers to check
+ * @param[in] f numbers to check
* @return true: if number set is bad, false: if set is okay (has unique
* prime factors)
*/
-static bool checkdivisors(const lst& f)
+static bool checkdivisors(const exvector& f)
{
- const int k = f.nops();
+ const int k = f.size();
numeric q, r;
vector<numeric> d(k);
- d[0] = ex_to<numeric>(abs(f.op(0)));
+ d[0] = ex_to<numeric>(abs(f[0]));
for ( int i=1; i<k; ++i ) {
- q = ex_to<numeric>(abs(f.op(i)));
+ q = ex_to<numeric>(abs(f[i]));
for ( int j=i-1; j>=0; --j ) {
r = d[j];
do {
*
* @param[in] u multivariate polynomial to be factored
* @param[in] vn leading coefficient of u in x (x==first symbol in syms)
- * @param[in] syms set of symbols that appear in u
- * @param[in] f lst containing the factors of the leading coefficient vn
+ * @param[in] x first symbol that appears in u
+ * @param[in] syms_wox remaining symbols that appear in u
+ * @param[in] f vector containing the factors of the leading coefficient vn
* @param[in,out] modulus integer modulus for random number generation (i.e. |a_i| < modulus)
* @param[out] u0 returns the evaluated (univariate) polynomial
* @param[out] a returns the valid evaluation points. must have initial size equal
* number of symbols-1 before calling generate_set
*/
-static void generate_set(const ex& u, const ex& vn, const exset& syms, const lst& f,
+static void generate_set(const ex& u, const ex& vn, const ex& x, const exset& syms_wox, const exvector& f,
numeric& modulus, ex& u0, vector<numeric>& a)
{
- const ex& x = *syms.begin();
while ( true ) {
++modulus;
// generate a set of integers ...
u0 = u;
ex vna = vn;
ex vnatry;
- exset::const_iterator s = syms.begin();
- ++s;
+ auto s = syms_wox.begin();
for ( size_t i=0; i<a.size(); ++i ) {
do {
a[i] = mod(numeric(rand()), 2*modulus) - modulus;
}
if ( !is_a<numeric>(vn) ) {
// ... and for which the evaluated factors have each an unique prime factor
- lst fnum = f;
- fnum.let_op(0) = fnum.op(0) * u0.content(x);
- for ( size_t i=1; i<fnum.nops(); ++i ) {
- if ( !is_a<numeric>(fnum.op(i)) ) {
- s = syms.begin();
- ++s;
+ exvector fnum = f;
+ fnum[0] = fnum[0] * u0.content(x);
+ for ( size_t i=1; i<fnum.size(); ++i ) {
+ if ( !is_a<numeric>(fnum[i]) ) {
+ s = syms_wox.begin();
for ( size_t j=0; j<a.size(); ++j, ++s ) {
- fnum.let_op(i) = fnum.op(i).subs(*s == a[j]);
+ fnum[i] = fnum[i].subs(*s == a[j]);
}
}
}
// forward declaration
static ex factor_sqrfree(const ex& poly);
-/** Multivariate factorization.
- *
- * The implementation is based on the algorithm described in [Wan].
- * An evaluation homomorphism (a set of integers) is determined that fulfills
- * certain criteria. The evaluated polynomial is univariate and is factorized
- * by factor_univariate(). The main work then is to find the correct leading
- * coefficients of the univariate factors. They have to correspond to the
- * factors of the (multivariate) leading coefficient of the input polynomial
- * (as defined for a specific variable x). After that the Hensel lifting can be
- * performed.
- *
- * @param[in] poly expanded, square free polynomial
- * @param[in] syms contains the symbols in the polynomial
- * @return factorized polynomial
+/** Used by factor_multivariate().
*/
-static ex factor_multivariate(const ex& poly, const exset& syms)
-{
- exset::const_iterator s;
- const ex& x = *syms.begin();
-
- // make polynomial primitive
- ex unit, cont, pp;
- poly.unitcontprim(x, unit, cont, pp);
- if ( !is_a<numeric>(cont) ) {
- return factor_sqrfree(cont) * factor_sqrfree(pp);
- }
-
- // factor leading coefficient
- ex vn = pp.collect(x).lcoeff(x);
- ex vnlst;
- if ( is_a<numeric>(vn) ) {
- vnlst = lst{vn};
- }
- else {
- ex vnfactors = factor(vn);
- vnlst = put_factors_into_lst(vnfactors);
- }
-
- const unsigned int maxtrials = 3;
- numeric modulus = (vnlst.nops() > 3) ? vnlst.nops() : 3;
- vector<numeric> a(syms.size()-1, 0);
-
- // try now to factorize until we are successful
- while ( true ) {
+struct factorization_ctx {
+ const ex poly, x; // polynomial, first symbol x...
+ const exset syms_wox; // ...remaining symbols w/o x
+ ex unit, cont, pp; // unit * cont * pp == poly
+ ex vn; exvector vnlst; // leading coeff, factors of leading coeff
+ numeric modulus; // incremented each time we try
+ /** returns factors or empty if it did not succeed */
+ ex try_next_evaluation_homomorphism()
+ {
+ constexpr unsigned maxtrials = 3;
+ vector<numeric> a(syms_wox.size(), 0);
unsigned int trialcount = 0;
unsigned int prime;
int factor_count = 0;
int min_factor_count = -1;
ex u, delta;
- ex ufac, ufaclst;
+ ex ufac;
+ exvector ufaclst;
// try several evaluation points to reduce the number of factors
while ( trialcount < maxtrials ) {
// generate a set of valid evaluation points
- generate_set(pp, vn, syms, ex_to<lst>(vnlst), modulus, u, a);
+ generate_set(pp, vn, x, syms_wox, vnlst, modulus, u, a);
ufac = factor_univariate(u, x, prime);
- ufaclst = put_factors_into_lst(ufac);
- factor_count = ufaclst.nops()-1;
- delta = ufaclst.op(0);
+ ufaclst = put_factors_into_vec(ufac);
+ factor_count = ufaclst.size()-1;
+ delta = ufaclst[0];
if ( factor_count <= 1 ) {
// irreducible
- return poly;
+ return lst{pp};
}
if ( min_factor_count < 0 ) {
// first time here
vector<ex> C(factor_count);
if ( is_a<numeric>(vn) ) {
// easy case
- for ( size_t i=1; i<ufaclst.nops(); ++i ) {
- C[i-1] = ufaclst.op(i).lcoeff(x);
+ for ( size_t i=1; i<ufaclst.size(); ++i ) {
+ C[i-1] = ufaclst[i].lcoeff(x);
}
} else {
// difficult case.
// we use the property of the ftilde having a unique prime factor.
// details can be found in [Wan].
// calculate ftilde
- vector<numeric> ftilde(vnlst.nops()-1);
+ vector<numeric> ftilde(vnlst.size()-1);
for ( size_t i=0; i<ftilde.size(); ++i ) {
- ex ft = vnlst.op(i+1);
- s = syms.begin();
- ++s;
+ ex ft = vnlst[i+1];
+ auto s = syms_wox.begin();
for ( size_t j=0; j<a.size(); ++j ) {
ft = ft.subs(*s == a[j]);
++s;
vector<ex> D(factor_count, 1);
if ( delta == 1 ) {
for ( int i=0; i<factor_count; ++i ) {
- numeric prefac = ex_to<numeric>(ufaclst.op(i+1).lcoeff(x));
+ numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(x));
for ( int j=ftilde.size()-1; j>=0; --j ) {
int count = 0;
- while ( irem(prefac, ftilde[j]) == 0 ) {
- prefac = iquo(prefac, ftilde[j]);
+ numeric q;
+ while ( irem(prefac, ftilde[j], q) == 0 ) {
+ prefac = q;
++count;
}
if ( count ) {
used_flag[j] = true;
- D[i] = D[i] * pow(vnlst.op(j+1), count);
+ D[i] = D[i] * pow(vnlst[j+1], count);
}
}
C[i] = D[i] * prefac;
}
} else {
for ( int i=0; i<factor_count; ++i ) {
- numeric prefac = ex_to<numeric>(ufaclst.op(i+1).lcoeff(x));
+ numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(x));
for ( int j=ftilde.size()-1; j>=0; --j ) {
int count = 0;
- while ( irem(prefac, ftilde[j]) == 0 ) {
- prefac = iquo(prefac, ftilde[j]);
+ numeric q;
+ while ( irem(prefac, ftilde[j], q) == 0 ) {
+ prefac = q;
++count;
}
while ( irem(ex_to<numeric>(delta)*prefac, ftilde[j]) == 0 ) {
numeric g = gcd(prefac, ex_to<numeric>(ftilde[j]));
prefac = iquo(prefac, g);
delta = delta / (ftilde[j]/g);
- ufaclst.let_op(i+1) = ufaclst.op(i+1) * (ftilde[j]/g);
+ ufaclst[i+1] = ufaclst[i+1] * (ftilde[j]/g);
++count;
}
if ( count ) {
used_flag[j] = true;
- D[i] = D[i] * pow(vnlst.op(j+1), count);
+ D[i] = D[i] * pow(vnlst[j+1], count);
}
}
C[i] = D[i] * prefac;
}
}
if ( some_factor_unused ) {
- continue;
+ return lst{}; // next try
}
}
-
+
// multiply the remaining content of the univariate polynomial into the
// first factor
if ( delta != 1 ) {
C[0] = C[0] * delta;
- ufaclst.let_op(1) = ufaclst.op(1) * delta;
+ ufaclst[1] = ufaclst[1] * delta;
}
// set up evaluation points
- EvalPoint ep;
vector<EvalPoint> epv;
- s = syms.begin();
- ++s;
+ auto s = syms_wox.begin();
for ( size_t i=0; i<a.size(); ++i ) {
- ep.x = *s++;
- ep.evalpoint = a[i].to_int();
- epv.push_back(ep);
+ epv.emplace_back(EvalPoint{*s++, a[i].to_int()});
}
// calc bound p^l
int maxdeg = 0;
for ( int i=1; i<=factor_count; ++i ) {
- if ( ufaclst.op(i).degree(x) > maxdeg ) {
+ if ( ufaclst[i].degree(x) > maxdeg ) {
maxdeg = ufaclst[i].degree(x);
}
}
- cl_I B = 2*calc_bound(u, x, maxdeg);
+ cl_I B = ash(calc_bound(u, x), maxdeg+1); // = 2 * calc_bound(u,x) * 2^maxdeg
cl_I l = 1;
cl_I pl = prime;
while ( pl < B ) {
l = l + 1;
pl = pl * prime;
}
-
+
// set up modular factors (mod p^l)
- cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
- upvec modfactors(ufaclst.nops()-1);
- for ( size_t i=1; i<ufaclst.nops(); ++i ) {
- umodpoly_from_ex(modfactors[i-1], ufaclst.op(i), x, R);
+ cl_modint_ring R = find_modint_ring(pl);
+ upvec modfactors(ufaclst.size()-1);
+ for ( size_t i=1; i<ufaclst.size(); ++i ) {
+ umodpoly_from_ex(modfactors[i-1], ufaclst[i], x, R);
}
// try Hensel lifting
- ex res = hensel_multivar(pp, x, epv, prime, l, modfactors, C);
+ return hensel_multivar(pp, x, epv, prime, l, modfactors, C);
+ }
+};
+
+/** Multivariate factorization.
+ *
+ * The implementation is based on the algorithm described in [Wan].
+ * An evaluation homomorphism (a set of integers) is determined that fulfills
+ * certain criteria. The evaluated polynomial is univariate and is factorized
+ * by factor_univariate(). The main work then is to find the correct leading
+ * coefficients of the univariate factors. They have to correspond to the
+ * factors of the (multivariate) leading coefficient of the input polynomial
+ * (as defined for a specific variable x). After that the Hensel lifting can be
+ * performed. This is done in round-robin for each x in syms until success.
+ *
+ * @param[in] poly expanded, square free polynomial
+ * @param[in] syms contains the symbols in the polynomial
+ * @return factorized polynomial
+ */
+static ex factor_multivariate(const ex& poly, const exset& syms)
+{
+ // set up one factorization context for each symbol
+ vector<factorization_ctx> ctx_in_x;
+ for (auto x : syms) {
+ exset syms_wox; // remaining syms w/o x
+ copy_if(syms.begin(), syms.end(),
+ inserter(syms_wox, syms_wox.end()), [x](const ex& y){ return y != x; });
+
+ factorization_ctx ctx{poly, x, syms_wox};
+
+ // make polynomial primitive
+ poly.unitcontprim(x, ctx.unit, ctx.cont, ctx.pp);
+ if ( !is_a<numeric>(ctx.cont) ) {
+ // content is a polynomial in one or more of remaining syms, let's start over
+ return ctx.unit * factor_sqrfree(ctx.cont) * factor_sqrfree(ctx.pp);
+ }
+
+ // find factors of leading coefficient
+ ctx.vn = ctx.pp.collect(x).lcoeff(x);
+ ctx.vnlst = put_factors_into_vec(factor(ctx.vn));
+
+ ctx.modulus = (ctx.vnlst.size() > 3) ? ctx.vnlst.size() : numeric(3);
+
+ ctx_in_x.push_back(ctx);
+ }
+
+ // try an evaluation homomorphism for each context in round-robin
+ auto ctx = ctx_in_x.begin();
+ while ( true ) {
+
+ ex res = ctx->try_next_evaluation_homomorphism();
+
if ( res != lst{} ) {
- ex result = cont * unit;
+ // found the factors
+ ex result = ctx->cont * ctx->unit;
for ( size_t i=0; i<res.nops(); ++i ) {
- result *= res.op(i).content(x) * res.op(i).unit(x);
- result *= res.op(i).primpart(x);
+ ex unit, cont, pp;
+ res.op(i).unitcontprim(ctx->x, unit, cont, pp);
+ result *= unit * cont * pp;
}
return result;
}
+
+ // switch context for next symbol
+ if (++ctx == ctx_in_x.end()) {
+ ctx = ctx_in_x.begin();
+ }
}
}
if ( findsymbols.syms.size() == 1 ) {
// univariate case
const ex& x = *(findsymbols.syms.begin());
- if ( poly.ldegree(x) > 0 ) {
+ int ld = poly.ldegree(x);
+ if ( ld > 0 ) {
// pull out direct factors
- int ld = poly.ldegree(x);
ex res = factor_univariate(expand(poly/pow(x, ld)), x);
return res * pow(x,ld);
} else {
}
} // namespace GiNaC
-
-#ifdef DEBUGFACTOR
-#include "test.h"
-#endif
* Polynomial factorization. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* functions or polynomials inside function arguments.
*
* @param[in] poly expression to factorize
- * @param[in] option options to influence the factorization
+ * @param[in] options see GiNaC::factor_options
* @return factorized expression
*/
extern ex factor(const ex& poly, unsigned options = 0);
* somewhat obsolete (most of this can be replaced by exceptions). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* somewhat obsolete (most of this can be replaced by exceptions). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of abstract derivatives of functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to abstract derivatives of functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Collection of all flags used through the GiNaC framework. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Please do not modify it directly, edit function.cppy instead!
* function.py options: maxargs=@maxargs@
*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
void function::read_archive(const archive_node& n, lst& sym_lst)
{
inherited::read_archive(n, sym_lst);
- // Find serial number by function name
+ // Find serial number by function name and number of parameters
+ unsigned np = seq.size();
std::string s;
if (n.find_string("name", s)) {
unsigned int ser = 0;
for (auto & it : registered_functions()) {
- if (s == it.name) {
+ if (s == it.name && np == registered_functions()[ser].nparams) {
serial = ser;
return;
}
++ser;
}
- throw (std::runtime_error("unknown function '" + s + "' in archive"));
+ throw (std::runtime_error("unknown function '" + s +
+ "' with " + std::to_string(np) + " parameters in archive"));
} else
throw (std::runtime_error("unnamed function in archive"));
}
}
current_serial = serial;
if (opt.evalf_use_exvector_args)
- return ((evalf_funcp_exvector)(opt.evalf_f))(seq);
+ return ((evalf_funcp_exvector)(opt.evalf_f))(eseq);
switch (opt.nparams) {
// the following lines have been generated for max. @maxargs@ parameters
+++ for N in range(1, maxargs + 1):
* This file was generated automatically from function.hppy.
* Please do not modify it directly, edit function.hppy instead!
*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
-#!/usr/bin/env python3
+
# encoding: utf-8
maxargs = 14
* This include file includes all other public GiNaC headers. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "factor.h"
+#include "integration_kernel.h"
+
#include "excompiler.h"
#ifndef IN_GINAC
* Replacement for map<> using hash tables. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's indices. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's indices. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/** Construct index with given value and dimension.
*
* @param v Value of index (numeric or symbolic)
- * @param dim Dimension of index space (numeric or symbolic)
- * @return newly constructed index */
+ * @param dim Dimension of index space (numeric or symbolic) */
explicit idx(const ex & v, const ex & dim);
// functions overriding virtual functions from base classes
*
* @param v Value of index (numeric or symbolic)
* @param dim Dimension of index space (numeric or symbolic)
- * @param covariant Make covariant index (default is contravariant)
- * @return newly constructed index */
+ * @param covariant Make covariant index (default is contravariant) */
varidx(const ex & v, const ex & dim, bool covariant = false);
// functions overriding virtual functions from base classes
* @param v Value of index (numeric or symbolic)
* @param dim Dimension of index space (numeric or symbolic)
* @param covariant Make covariant index (default is contravariant)
- * @param dotted Make covariant dotted (default is undotted)
- * @return newly constructed index */
+ * @param dotted Make covariant dotted (default is undotted) */
spinidx(const ex & v, const ex & dim = 2, bool covariant = false, bool dotted = false);
// functions overriding virtual functions from base classes
* Implementation of GiNaC's indexed expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's indexed expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
public:
/** Construct indexed object with no index.
*
- * @param b Base expression
- * @return newly constructed indexed object */
+ * @param b Base expression */
indexed(const ex & b);
/** Construct indexed object with one index. The index must be of class idx.
*
* @param b Base expression
- * @param i1 The index
- * @return newly constructed indexed object */
+ * @param i1 The index */
indexed(const ex & b, const ex & i1);
/** Construct indexed object with two indices. The indices must be of class idx.
*
* @param b Base expression
* @param i1 First index
- * @param i2 Second index
- * @return newly constructed indexed object */
+ * @param i2 Second index */
indexed(const ex & b, const ex & i1, const ex & i2);
/** Construct indexed object with three indices. The indices must be of class idx.
* @param b Base expression
* @param i1 First index
* @param i2 Second index
- * @param i3 Third index
- * @return newly constructed indexed object */
+ * @param i3 Third index */
indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3);
/** Construct indexed object with four indices. The indices must be of class idx.
* @param i1 First index
* @param i2 Second index
* @param i3 Third index
- * @param i4 Fourth index
- * @return newly constructed indexed object */
+ * @param i4 Fourth index */
indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3, const ex & i4);
/** Construct indexed object with two indices and a specified symmetry. The
* @param b Base expression
* @param symm Symmetry of indices
* @param i1 First index
- * @param i2 Second index
- * @return newly constructed indexed object */
+ * @param i2 Second index */
indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2);
/** Construct indexed object with three indices and a specified symmetry.
* @param symm Symmetry of indices
* @param i1 First index
* @param i2 Second index
- * @param i3 Third index
- * @return newly constructed indexed object */
+ * @param i3 Third index */
indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2, const ex & i3);
/** Construct indexed object with four indices and a specified symmetry. The
* @param i1 First index
* @param i2 Second index
* @param i3 Third index
- * @param i4 Fourth index
- * @return newly constructed indexed object */
+ * @param i4 Fourth index */
indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2, const ex & i3, const ex & i4);
/** Construct indexed object with a specified vector of indices. The indices
* must be of class idx.
*
* @param b Base expression
- * @param iv Vector of indices
- * @return newly constructed indexed object */
+ * @param iv Vector of indices */
indexed(const ex & b, const exvector & iv);
/** Construct indexed object with a specified vector of indices and
*
* @param b Base expression
* @param symm Symmetry of indices
- * @param iv Vector of indices
- * @return newly constructed indexed object */
+ * @param iv Vector of indices */
indexed(const ex & b, const symmetry & symm, const exvector & iv);
// internal constructors
* Implementation of GiNaC's initially known functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
return Order(x).hold();
}
+static ex Order_power(const ex & x, const ex & e)
+{
+ // Order(x)^e -> Order(x^e) for positive integer e
+ if (is_exactly_a<numeric>(e) && e.info(info_flags::posint))
+ return Order(pow(x, e));
+ // NB: For negative exponents, the above could be wrong.
+ // This is because series() produces Order(x^n) to denote the order where
+ // it gave up. So, Order(x^n) can also be an x^(n+1) term if the x^n term
+ // vanishes. In this situation, 1/Order(x^n) can also be a x^(-n-1) term.
+ // Transforming it to Order(x^-n) would miss that.
+
+ return power(Order(x), e).hold();
+}
+
static ex Order_expl_derivative(const ex & arg, const symbol & s)
{
return Order(arg.diff(s));
expl_derivative_func(Order_expl_derivative).
conjugate_func(Order_conjugate).
real_part_func(Order_real_part).
- imag_part_func(Order_imag_part));
+ imag_part_func(Order_imag_part).
+ power_func(Order_power));
//////////
// Solve linear system
* Interface to GiNaC's initially known functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
return is_the_function<psi1_SERIAL>(x) || is_the_function<psi2_SERIAL>(x);
}
+/** Complete elliptic integral of the first kind. */
+DECLARE_FUNCTION_1P(EllipticK)
+
+/** Complete elliptic integral of the second kind. */
+DECLARE_FUNCTION_1P(EllipticE)
+
+// overloading at work: we cannot use the macros here
+/** Iterated integral. */
+class iterated_integral2_SERIAL { public: static unsigned serial; };
+template<typename T1, typename T2>
+inline function iterated_integral(const T1& kernel_lst, const T2& lambda) {
+ return function(iterated_integral2_SERIAL::serial, ex(kernel_lst), ex(lambda));
+}
+/** Iterated integral with explicit truncation. */
+class iterated_integral3_SERIAL { public: static unsigned serial; };
+template<typename T1, typename T2, typename T3>
+inline function iterated_integral(const T1& kernel_lst, const T2& lambda, const T3& N_trunc) {
+ return function(iterated_integral3_SERIAL::serial, ex(kernel_lst), ex(lambda), ex(N_trunc));
+}
+class iterated_integral_SERIAL;
+template<> inline bool is_the_function<iterated_integral_SERIAL>(const ex& x)
+{
+ return is_the_function<iterated_integral2_SERIAL>(x) || is_the_function<iterated_integral3_SERIAL>(x);
+}
+
+
/** Factorial function. */
DECLARE_FUNCTION_1P(factorial)
--- /dev/null
+/** @file inifcns_elliptic.cpp
+ *
+ * Implementation of some special functions related to elliptic curves
+ *
+ * The functions are:
+ * complete elliptic integral of the first kind EllipticK(k)
+ * complete elliptic integral of the second kind EllipticE(k)
+ * iterated integral iterated_integral(a,y) or iterated_integral(a,y,N_trunc)
+ *
+ * Some remarks:
+ *
+ * - All formulae used can be looked up in the following publication:
+ * [WW] Numerical evaluation of iterated integrals related to elliptic Feynman integrals, M.Walden, S.Weinzierl, arXiv:2010.05271
+ *
+ * - When these routines and methods are used for scientific work that leads to publication in a scientific journal,
+ * please refer to this program as :
+ * M.Walden, S.Weinzierl, "Numerical evaluation of iterated integrals related to elliptic Feynman integrals", arXiv:2010.05271
+ *
+ * - As these routines build on the core part of GiNaC, it is also polite to acknowledge
+ * C. Bauer, A. Frink, R. Kreckel, "Introduction to the GiNaC Framework for Symbolic Computation within the C++ Programming Language",
+ * J. Symbolic Computations 33, 1 (2002), cs.sc/0004015
+ *
+ */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "inifcns.h"
+
+#include "add.h"
+#include "constant.h"
+#include "lst.h"
+#include "mul.h"
+#include "numeric.h"
+#include "operators.h"
+#include "power.h"
+#include "pseries.h"
+#include "relational.h"
+#include "symbol.h"
+#include "utils.h"
+#include "wildcard.h"
+
+#include "integration_kernel.h"
+#include "utils_multi_iterator.h"
+
+#include <cln/cln.h>
+#include <sstream>
+#include <stdexcept>
+#include <vector>
+#include <cmath>
+
+namespace GiNaC {
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Complete elliptic integrals
+//
+// helper functions
+//
+//////////////////////////////////////////////////////////////////////
+
+
+// anonymous namespace for helper function
+namespace {
+
+// Computes the arithmetic geometric of two numbers a_0 and b_0
+cln::cl_N arithmetic_geometric_mean(const cln::cl_N & a_0, const cln::cl_N & b_0)
+{
+ cln::cl_N a_old = a_0 * cln::cl_float(1, cln::float_format(Digits));
+ cln::cl_N b_old = b_0 * cln::cl_float(1, cln::float_format(Digits));
+ cln::cl_N a_new;
+ cln::cl_N b_new;
+ cln::cl_N res = a_old;
+ cln::cl_N resbuf;
+ do {
+ resbuf = res;
+
+ a_new = (a_old+b_old)/2;
+ b_new = sqrt(a_old*b_old);
+
+ if ( ( abs(a_new-b_new) > abs(a_new+b_new) )
+ ||
+ ( (abs(a_new-b_new) == abs(a_new+b_new)) && (imagpart(b_new/a_new) <= 0) ) ) {
+ b_new *= -1;
+ }
+
+ res = a_new;
+ a_old = a_new;
+ b_old = b_new;
+
+ } while (res != resbuf);
+ return res;
+}
+
+// Computes
+// a0^2 - sum_{n=0}^infinity 2^{n-1}*c_n^2
+// with
+// c_{n+1} = c_n^2/4/a_{n+1}
+//
+// Needed for the complete elliptic integral of the second kind.
+//
+cln::cl_N agm_helper_second_kind(const cln::cl_N & a_0, const cln::cl_N & b_0, const cln::cl_N & c_0)
+{
+ cln::cl_N a_old = a_0 * cln::cl_float(1, cln::float_format(Digits));
+ cln::cl_N b_old = b_0 * cln::cl_float(1, cln::float_format(Digits));
+ cln::cl_N c_old = c_0 * cln::cl_float(1, cln::float_format(Digits));
+ cln::cl_N a_new;
+ cln::cl_N b_new;
+ cln::cl_N c_new;
+ cln::cl_N res = square(a_old)-square(c_old)/2;
+ cln::cl_N resbuf;
+ cln::cl_N pre = cln::cl_float(1, cln::float_format(Digits));
+ do {
+ resbuf = res;
+
+ a_new = (a_old+b_old)/2;
+ b_new = sqrt(a_old*b_old);
+
+ if ( ( abs(a_new-b_new) > abs(a_new+b_new) )
+ ||
+ ( (abs(a_new-b_new) == abs(a_new+b_new)) && (imagpart(b_new/a_new) <= 0) ) ) {
+ b_new *= -1;
+ }
+
+ c_new = square(c_old)/4/a_new;
+
+ res -= pre*square(c_new);
+
+ a_old = a_new;
+ b_old = b_new;
+ c_old = c_new;
+ pre *= 2;
+
+ } while (res != resbuf);
+ return res;
+}
+
+
+} // end of anonymous namespace
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Complete elliptic integrals
+//
+// GiNaC function
+//
+//////////////////////////////////////////////////////////////////////
+
+static ex EllipticK_evalf(const ex& k)
+{
+ if ( !k.info(info_flags::numeric) ) {
+ return EllipticK(k).hold();
+ }
+
+ cln::cl_N kbar = sqrt(1-square(ex_to<numeric>(k).to_cl_N()));
+
+ ex result = Pi/2/numeric(arithmetic_geometric_mean(1,kbar));
+
+ return result.evalf();
+}
+
+
+static ex EllipticK_eval(const ex& k)
+{
+ if (k == _ex0) {
+ return Pi/2;
+ }
+
+ if ( k.info(info_flags::numeric) && !k.info(info_flags::crational) ) {
+ return EllipticK(k).evalf();
+ }
+
+ return EllipticK(k).hold();
+}
+
+
+static ex EllipticK_deriv(const ex& k, unsigned deriv_param)
+{
+ return -EllipticK(k)/k + EllipticE(k)/k/(1-k*k);
+}
+
+
+static ex EllipticK_series(const ex& k, const relational& rel, int order, unsigned options)
+{
+ const ex k_pt = k.subs(rel, subs_options::no_pattern);
+
+ if (k_pt == _ex0) {
+ const symbol s;
+ ex ser;
+ // manually construct the primitive expansion
+ for (int i=0; i<(order+1)/2; ++i)
+ {
+ ser += Pi/2 * numeric(cln::square(cln::binomial(2*i,i))) * pow(s/4,2*i);
+ }
+ // substitute the argument's series expansion
+ ser = ser.subs(s==k.series(rel, order), subs_options::no_pattern);
+ // maybe that was terminating, so add a proper order term
+ epvector nseq { expair(Order(_ex1), order) };
+ ser += pseries(rel, std::move(nseq));
+ // reexpanding it will collapse the series again
+ return ser.series(rel, order);
+ }
+
+ if ( (k_pt == _ex1) || (k_pt == _ex_1) ) {
+ throw std::runtime_error("EllipticK_series: don't know how to do the series expansion at this point!");
+ }
+
+ // all other cases
+ throw do_taylor();
+}
+
+static void EllipticK_print_latex(const ex& k, const print_context& c)
+{
+ c.s << "\\mathrm{K}(";
+ k.print(c);
+ c.s << ")";
+}
+
+
+REGISTER_FUNCTION(EllipticK,
+ evalf_func(EllipticK_evalf).
+ eval_func(EllipticK_eval).
+ derivative_func(EllipticK_deriv).
+ series_func(EllipticK_series).
+ print_func<print_latex>(EllipticK_print_latex).
+ do_not_evalf_params());
+
+
+static ex EllipticE_evalf(const ex& k)
+{
+ if ( !k.info(info_flags::numeric) ) {
+ return EllipticE(k).hold();
+ }
+
+ cln::cl_N kbar = sqrt(1-square(ex_to<numeric>(k).to_cl_N()));
+
+ ex result = Pi/2 * numeric( agm_helper_second_kind(1,kbar,ex_to<numeric>(k).to_cl_N()) / arithmetic_geometric_mean(1,kbar) );
+
+ return result.evalf();
+}
+
+
+static ex EllipticE_eval(const ex& k)
+{
+ if (k == _ex0) {
+ return Pi/2;
+ }
+
+ if ( (k == _ex1) || (k == _ex_1) ) {
+ return 1;
+ }
+
+ if ( k.info(info_flags::numeric) && !k.info(info_flags::crational) ) {
+ return EllipticE(k).evalf();
+ }
+
+ return EllipticE(k).hold();
+}
+
+
+static ex EllipticE_deriv(const ex& k, unsigned deriv_param)
+{
+ return -EllipticK(k)/k + EllipticE(k)/k;
+}
+
+
+static ex EllipticE_series(const ex& k, const relational& rel, int order, unsigned options)
+{
+ const ex k_pt = k.subs(rel, subs_options::no_pattern);
+
+ if (k_pt == _ex0) {
+ const symbol s;
+ ex ser;
+ // manually construct the primitive expansion
+ for (int i=0; i<(order+1)/2; ++i)
+ {
+ ser -= Pi/2 * numeric(cln::square(cln::binomial(2*i,i)))/(2*i-1) * pow(s/4,2*i);
+ }
+ // substitute the argument's series expansion
+ ser = ser.subs(s==k.series(rel, order), subs_options::no_pattern);
+ // maybe that was terminating, so add a proper order term
+ epvector nseq { expair(Order(_ex1), order) };
+ ser += pseries(rel, std::move(nseq));
+ // reexpanding it will collapse the series again
+ return ser.series(rel, order);
+ }
+
+ if ( (k_pt == _ex1) || (k_pt == _ex_1) ) {
+ throw std::runtime_error("EllipticE_series: don't know how to do the series expansion at this point!");
+ }
+
+ // all other cases
+ throw do_taylor();
+}
+
+static void EllipticE_print_latex(const ex& k, const print_context& c)
+{
+ c.s << "\\mathrm{K}(";
+ k.print(c);
+ c.s << ")";
+}
+
+
+REGISTER_FUNCTION(EllipticE,
+ evalf_func(EllipticE_evalf).
+ eval_func(EllipticE_eval).
+ derivative_func(EllipticE_deriv).
+ series_func(EllipticE_series).
+ print_func<print_latex>(EllipticE_print_latex).
+ do_not_evalf_params());
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Iterated integrals
+//
+// helper functions
+//
+//////////////////////////////////////////////////////////////////////
+
+// anonymous namespace for helper function
+namespace {
+
+// performs the actual series summation for an iterated integral
+cln::cl_N iterated_integral_do_sum(const std::vector<int> & m, const std::vector<const integration_kernel *> & kernel, const cln::cl_N & lambda, int N_trunc)
+{
+ if ( cln::zerop(lambda) ) {
+ return 0;
+ }
+
+ cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
+
+ const int depth = m.size();
+
+ cln::cl_N res = 0;
+ cln::cl_N resbuf;
+ cln::cl_N subexpr;
+
+ if ( N_trunc == 0 ) {
+ // sum until precision is reached
+ bool flag_accidental_zero = false;
+
+ int N = 1;
+
+ do {
+ resbuf = res;
+
+ if ( depth > 1 ) {
+ subexpr = 0;
+ multi_iterator_ordered_eq<int> i_multi(1,N+1,depth-1);
+ for( i_multi.init(); !i_multi.overflow(); i_multi++) {
+ cln::cl_N tt = one;
+ for (int j=1; j<depth; j++) {
+ if ( j==1 ) {
+ tt = tt * kernel[0]->series_coeff(N-i_multi[depth-2]) / cln::expt(cln::cl_I(i_multi[depth-2]),m[1]);
+ }
+ else {
+ tt = tt * kernel[j-1]->series_coeff(i_multi[depth-j]-i_multi[depth-j-1]) / cln::expt(cln::cl_I(i_multi[depth-j-1]),m[j]);
+ }
+ }
+ tt = tt * kernel[depth-1]->series_coeff(i_multi[0]);
+ subexpr += tt;
+ }
+ }
+ else {
+ // depth == 1
+ subexpr = kernel[0]->series_coeff(N) * one;
+ }
+ flag_accidental_zero = cln::zerop(subexpr);
+ res += cln::expt(lambda, N) / cln::expt(cln::cl_I(N),m[0]) * subexpr;
+ N++;
+
+ } while ( (res != resbuf) || flag_accidental_zero );
+ }
+ else {
+ // N_trunc > 0, sum up the first N_trunc terms
+ for (int N=1; N<=N_trunc; N++) {
+ if ( depth > 1 ) {
+ subexpr = 0;
+ multi_iterator_ordered_eq<int> i_multi(1,N+1,depth-1);
+ for( i_multi.init(); !i_multi.overflow(); i_multi++) {
+ cln::cl_N tt = one;
+ for (int j=1; j<depth; j++) {
+ if ( j==1 ) {
+ tt = tt * kernel[0]->series_coeff(N-i_multi[depth-2]) / cln::expt(cln::cl_I(i_multi[depth-2]),m[1]);
+ }
+ else {
+ tt = tt * kernel[j-1]->series_coeff(i_multi[depth-j]-i_multi[depth-j-1]) / cln::expt(cln::cl_I(i_multi[depth-j-1]),m[j]);
+ }
+ }
+ tt = tt * kernel[depth-1]->series_coeff(i_multi[0]);
+ subexpr += tt;
+ }
+ }
+ else {
+ // depth == 1
+ subexpr = kernel[0]->series_coeff(N) * one;
+ }
+ res += cln::expt(lambda, N) / cln::expt(cln::cl_I(N),m[0]) * subexpr;
+ }
+ }
+
+ return res;
+}
+
+// figure out the number of basic_log_kernels before a non-basic_log_kernel
+cln::cl_N iterated_integral_prepare_m_lst(const std::vector<const integration_kernel *> & kernel_in, const cln::cl_N & lambda, int N_trunc)
+{
+ size_t depth = kernel_in.size();
+
+ std::vector<int> m;
+ m.reserve(depth);
+
+ std::vector<const integration_kernel *> kernel;
+ kernel.reserve(depth);
+
+ int n = 1;
+
+ for (const auto & it : kernel_in) {
+ if ( is_a<basic_log_kernel>(*it) ) {
+ n++;
+ }
+ else {
+ m.push_back(n);
+ kernel.push_back( &ex_to<integration_kernel>(*it) );
+ n = 1;
+ }
+ }
+
+ cln::cl_N result = iterated_integral_do_sum(m, kernel, lambda, N_trunc);
+
+ return result;
+}
+
+// shuffle to remove trailing zeros,
+// integration kernels, which are not basic_log_kernels, are treated as regularised kernels
+cln::cl_N iterated_integral_shuffle(const std::vector<const integration_kernel *> & kernel, const cln::cl_N & lambda, int N_trunc)
+{
+ cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
+
+ const size_t depth = kernel.size();
+
+ size_t i_trailing = 0;
+ for (size_t i=0; i<depth; i++) {
+ if ( !(is_a<basic_log_kernel>(*(kernel[i]))) ) {
+ i_trailing = i+1;
+ }
+ }
+
+ if ( i_trailing == 0 ) {
+ return cln::expt(cln::log(lambda), depth) / cln::factorial(depth) * one;
+ }
+
+ if ( i_trailing == depth ) {
+ return iterated_integral_prepare_m_lst(kernel, lambda, N_trunc);
+ }
+
+ // shuffle
+ std::vector<const integration_kernel *> a,b;
+ for (size_t i=0; i<i_trailing; i++) {
+ a.push_back(kernel[i]);
+ }
+ for (size_t i=i_trailing; i<depth; i++) {
+ b.push_back(kernel[i]);
+ }
+
+ cln::cl_N result = iterated_integral_prepare_m_lst(a, lambda, N_trunc) * cln::expt(cln::log(lambda), depth-i_trailing) / cln::factorial(depth-i_trailing);
+ multi_iterator_shuffle_prime<const integration_kernel *> i_shuffle(a,b);
+ for( i_shuffle.init(); !i_shuffle.overflow(); i_shuffle++) {
+ std::vector<const integration_kernel *> new_kernel;
+ new_kernel.reserve(depth);
+ for (size_t i=0; i<depth; i++) {
+ new_kernel.push_back(i_shuffle[i]);
+ }
+
+ result -= iterated_integral_shuffle(new_kernel, lambda, N_trunc);
+ }
+
+ return result;
+}
+
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////
+//
+// Iterated integrals
+//
+// GiNaC function
+//
+//////////////////////////////////////////////////////////////////////
+
+static ex iterated_integral_evalf_impl(const ex& kernel_lst, const ex& lambda, const ex& N_trunc)
+{
+ // sanity check
+ if ((!kernel_lst.info(info_flags::list)) || (!lambda.evalf().info(info_flags::numeric)) || (!N_trunc.info(info_flags::nonnegint))) {
+ return iterated_integral(kernel_lst,lambda,N_trunc).hold();
+ }
+
+ lst k_lst = ex_to<lst>(kernel_lst);
+
+ bool flag_not_numeric = false;
+ for (const auto & it : k_lst) {
+ if ( !is_a<integration_kernel>(it) ) {
+ flag_not_numeric = true;
+ }
+ }
+ if ( flag_not_numeric) {
+ return iterated_integral(kernel_lst,lambda,N_trunc).hold();
+ }
+
+ for (const auto & it : k_lst) {
+ if ( !(ex_to<integration_kernel>(it).is_numeric()) ) {
+ flag_not_numeric = true;
+ }
+ }
+ if ( flag_not_numeric) {
+ return iterated_integral(kernel_lst,lambda,N_trunc).hold();
+ }
+
+ // now we know that iterated_integral gives a number
+
+ int N_trunc_int = ex_to<numeric>(N_trunc).to_int();
+
+ // check trailing zeros
+ const size_t depth = k_lst.nops();
+
+ std::vector<const integration_kernel *> kernel_vec;
+ kernel_vec.reserve(depth);
+
+ for (const auto & it : k_lst) {
+ kernel_vec.push_back( &ex_to<integration_kernel>(it) );
+ }
+
+ size_t i_trailing = 0;
+ for (size_t i=0; i<depth; i++) {
+ if ( !(kernel_vec[i]->has_trailing_zero()) ) {
+ i_trailing = i+1;
+ }
+ }
+
+ // split integral into regularised integrals and trailing basic_log_kernels
+ // non-basic_log_kernels are treated as regularised kernels in call to iterated_integral_shuffle
+ cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
+ cln::cl_N lambda_cln = ex_to<numeric>(lambda.evalf()).to_cl_N();
+ basic_log_kernel L0 = basic_log_kernel();
+
+ cln::cl_N result;
+ if ( is_a<basic_log_kernel>(*(kernel_vec[depth-1])) ) {
+ result = 0;
+ }
+ else {
+ result = iterated_integral_shuffle(kernel_vec, lambda_cln, N_trunc_int);
+ }
+
+ cln::cl_N coeff = one;
+ for (size_t i_plus=depth; i_plus>i_trailing; i_plus--) {
+ coeff = coeff * kernel_vec[i_plus-1]->series_coeff(0);
+ kernel_vec[i_plus-1] = &L0;
+ if ( i_plus==i_trailing+1 ) {
+ result += coeff * iterated_integral_shuffle(kernel_vec, lambda_cln, N_trunc_int);
+ }
+ else {
+ if ( !(is_a<basic_log_kernel>(*(kernel_vec[i_plus-2]))) ) {
+ result += coeff * iterated_integral_shuffle(kernel_vec, lambda_cln, N_trunc_int);
+ }
+ }
+ }
+
+ return numeric(result);
+}
+
+static ex iterated_integral2_evalf(const ex& kernel_lst, const ex& lambda)
+{
+ return iterated_integral_evalf_impl(kernel_lst,lambda,0);
+}
+
+static ex iterated_integral3_evalf(const ex& kernel_lst, const ex& lambda, const ex& N_trunc)
+{
+ return iterated_integral_evalf_impl(kernel_lst,lambda,N_trunc);
+}
+
+static ex iterated_integral2_eval(const ex& kernel_lst, const ex& lambda)
+{
+ if ( lambda.info(info_flags::numeric) && !lambda.info(info_flags::crational) ) {
+ return iterated_integral(kernel_lst,lambda).evalf();
+ }
+
+ return iterated_integral(kernel_lst,lambda).hold();
+}
+
+static ex iterated_integral3_eval(const ex& kernel_lst, const ex& lambda, const ex& N_trunc)
+{
+ if ( lambda.info(info_flags::numeric) && !lambda.info(info_flags::crational) ) {
+ return iterated_integral(kernel_lst,lambda,N_trunc).evalf();
+ }
+
+ return iterated_integral(kernel_lst,lambda,N_trunc).hold();
+}
+
+unsigned iterated_integral2_SERIAL::serial =
+ function::register_new(function_options("iterated_integral", 2).
+ eval_func(iterated_integral2_eval).
+ evalf_func(iterated_integral2_evalf).
+ do_not_evalf_params().
+ overloaded(2));
+
+unsigned iterated_integral3_SERIAL::serial =
+ function::register_new(function_options("iterated_integral", 3).
+ eval_func(iterated_integral3_eval).
+ evalf_func(iterated_integral3_evalf).
+ do_not_evalf_params().
+ overloaded(2));
+
+} // namespace GiNaC
+
* some related stuff. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
for (std::size_t i = 0; i < size; ++i)
x[i] = x[i]/y;
+ // 24.03.2021: this block can be outside the loop over r
+ cln::cl_RA p(2);
+ bool adjustp;
+ do {
+ adjustp = false;
+ for (std::size_t i = 0; i < size; ++i) {
+ // 24.03.2021: replaced (x[i] == cln::cl_RA(1)/p) by (cln::zerop(x[i] - cln::cl_RA(1)/p)
+ // in the case where we compare a float with a rational, CLN behaves differently in the two versions
+ if (cln::zerop(x[i] - cln::cl_RA(1)/p) ) {
+ p = p/2 + cln::cl_RA(3)/2;
+ adjustp = true;
+ continue;
+ }
+ }
+ } while (adjustp);
+ cln::cl_RA q = p/(p-1);
+
for (std::size_t r = 0; r <= size; ++r) {
cln::cl_N buffer(1 & r ? -1 : 1);
- cln::cl_RA p(2);
- bool adjustp;
- do {
- adjustp = false;
- for (std::size_t i = 0; i < size; ++i) {
- if (x[i] == cln::cl_RA(1)/p) {
- p = p/2 + cln::cl_RA(3)/2;
- adjustp = true;
- continue;
- }
- }
- } while (adjustp);
- cln::cl_RA q = p/(p-1);
std::vector<cln::cl_N> qlstx;
std::vector<int> qlsts;
for (std::size_t j = r; j >= 1; --j) {
// x -> 1-x
if (has_minus_one) {
map_trafo_H_convert_to_Li filter;
- return filter(H(m, numeric(x)).hold()).evalf();
+ // 09.06.2021: bug fix: don't forget a possible minus sign from the case realpart(x) < 0
+ res *= filter(H(m, numeric(x)).hold()).evalf();
+ return res;
}
map_trafo_H_1mx trafo;
res *= trafo(H(m, xtemp).hold());
return numeric(zeta_do_Hoelder_convolution(xi, si));
}
- return zeta(x, s).hold();
+ // x and s are not lists: convert to lists
+ return zeta(lst{x}, lst{s}).evalf();
}
* functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
return exp(x.conjugate());
}
+static ex exp_power(const ex & x, const ex & a)
+{
+ /*
+ * The power law (e^x)^a=e^(x*a) is used in two cases:
+ * a) a is an integer and x may be complex;
+ * b) both x and a are reals.
+ * Negative a is excluded to keep automatic simplifications like exp(x)/exp(x)=1.
+ */
+ if (a.info(info_flags::nonnegative)
+ && (a.info(info_flags::integer) || (x.info(info_flags::real) && a.info(info_flags::real))))
+ return exp(x*a);
+ else if (a.info(info_flags::negative)
+ && (a.info(info_flags::integer) || (x.info(info_flags::real) && a.info(info_flags::real))))
+ return power(exp(-x*a), _ex_1).hold();
+
+ return power(exp(x), a).hold();
+}
+
+static bool exp_info(const ex & x, unsigned inf)
+{
+ switch (inf) {
+ case info_flags::expanded:
+ case info_flags::real:
+ return x.info(inf);
+ case info_flags::positive:
+ case info_flags::nonnegative:
+ return x.info(info_flags::real);
+ default:
+ return false;
+ }
+}
+
REGISTER_FUNCTION(exp, eval_func(exp_eval).
evalf_func(exp_evalf).
+ info_func(exp_info).
expand_func(exp_expand).
derivative_func(exp_deriv).
real_part_func(exp_real_part).
imag_part_func(exp_imag_part).
conjugate_func(exp_conjugate).
+ power_func(exp_power).
latex_name("\\exp"));
//////////
// maybe substitution of rel into arg fails because of a pole
try {
arg_pt = arg.subs(rel, subs_options::no_pattern);
- } catch (pole_error) {
+ } catch (pole_error &) {
must_expand_arg = true;
}
// or we are at the branch point anyways
return conjugate_function(log(x)).hold();
}
+static bool log_info(const ex & x, unsigned inf)
+{
+ switch (inf) {
+ case info_flags::expanded:
+ return x.info(inf);
+ case info_flags::real:
+ return x.info(info_flags::positive);
+ default:
+ return false;
+ }
+}
+
REGISTER_FUNCTION(log, eval_func(log_eval).
evalf_func(log_evalf).
+ info_func(log_info).
expand_func(log_expand).
derivative_func(log_deriv).
series_func(log_series).
return sin(x.conjugate());
}
+static bool trig_info(const ex & x, unsigned inf)
+{
+ switch (inf) {
+ case info_flags::expanded:
+ case info_flags::real:
+ return x.info(inf);
+ default:
+ return false;
+ }
+}
+
REGISTER_FUNCTION(sin, eval_func(sin_eval).
evalf_func(sin_evalf).
+ info_func(trig_info).
derivative_func(sin_deriv).
real_part_func(sin_real_part).
imag_part_func(sin_imag_part).
}
REGISTER_FUNCTION(cos, eval_func(cos_eval).
+ info_func(trig_info).
evalf_func(cos_evalf).
derivative_func(cos_deriv).
real_part_func(cos_real_part).
REGISTER_FUNCTION(tan, eval_func(tan_eval).
evalf_func(tan_evalf).
+ info_func(trig_info).
derivative_func(tan_deriv).
series_func(tan_series).
real_part_func(tan_real_part).
return conjugate_function(asin(x)).hold();
}
+static bool asin_info(const ex & x, unsigned inf)
+{
+ switch (inf) {
+ case info_flags::expanded:
+ return x.info(inf);
+ default:
+ return false;
+ }
+}
+
REGISTER_FUNCTION(asin, eval_func(asin_eval).
evalf_func(asin_evalf).
+ info_func(asin_info).
derivative_func(asin_deriv).
conjugate_func(asin_conjugate).
latex_name("\\arcsin"));
REGISTER_FUNCTION(acos, eval_func(acos_eval).
evalf_func(acos_evalf).
+ info_func(asin_info). // Flags of acos are shared with asin functions
derivative_func(acos_deriv).
conjugate_func(acos_conjugate).
latex_name("\\arccos"));
return conjugate_function(atan(x)).hold();
}
+static bool atan_info(const ex & x, unsigned inf)
+{
+ switch (inf) {
+ case info_flags::expanded:
+ case info_flags::real:
+ return x.info(inf);
+ case info_flags::positive:
+ case info_flags::negative:
+ case info_flags::nonnegative:
+ return x.info(info_flags::real) && x.info(inf);
+ default:
+ return false;
+ }
+}
+
REGISTER_FUNCTION(atan, eval_func(atan_eval).
evalf_func(atan_evalf).
+ info_func(atan_info).
derivative_func(atan_deriv).
series_func(atan_series).
conjugate_func(atan_conjugate).
return -y*power(power(x,_ex2)+power(y,_ex2),_ex_1);
}
+static bool atan2_info(const ex & y, const ex & x, unsigned inf)
+{
+ switch (inf) {
+ case info_flags::expanded:
+ case info_flags::real:
+ return y.info(inf) && x.info(inf);
+ case info_flags::positive:
+ case info_flags::negative:
+ case info_flags::nonnegative:
+ return y.info(info_flags::real) && x.info(info_flags::real)
+ && y.info(inf);
+ default:
+ return false;
+ }
+}
+
REGISTER_FUNCTION(atan2, eval_func(atan2_eval).
+ evalf_func(atan2_evalf).
+ info_func(atan2_info).
evalf_func(atan2_evalf).
derivative_func(atan2_deriv));
REGISTER_FUNCTION(sinh, eval_func(sinh_eval).
evalf_func(sinh_evalf).
+ info_func(atan_info). // Flags of sinh are shared with atan functions
derivative_func(sinh_deriv).
real_part_func(sinh_real_part).
imag_part_func(sinh_imag_part).
REGISTER_FUNCTION(cosh, eval_func(cosh_eval).
evalf_func(cosh_evalf).
+ info_func(exp_info). // Flags of cosh are shared with exp functions
derivative_func(cosh_deriv).
real_part_func(cosh_real_part).
imag_part_func(cosh_imag_part).
REGISTER_FUNCTION(tanh, eval_func(tanh_eval).
evalf_func(tanh_evalf).
+ info_func(atan_info). // Flags of tanh are shared with atan functions
derivative_func(tanh_deriv).
series_func(tanh_series).
real_part_func(tanh_real_part).
REGISTER_FUNCTION(asinh, eval_func(asinh_eval).
evalf_func(asinh_evalf).
+ info_func(atan_info). // Flags of asinh are shared with atan functions
derivative_func(asinh_deriv).
conjugate_func(asinh_conjugate));
REGISTER_FUNCTION(acosh, eval_func(acosh_eval).
evalf_func(acosh_evalf).
+ info_func(asin_info). // Flags of acosh are shared with asin functions
derivative_func(acosh_deriv).
conjugate_func(acosh_conjugate));
REGISTER_FUNCTION(atanh, eval_func(atanh_eval).
evalf_func(atanh_evalf).
+ info_func(asin_info). // Flags of atanh are shared with asin functions
derivative_func(atanh_deriv).
series_func(atanh_series).
conjugate_func(atanh_conjugate));
* Implementation of GiNaC's symbolic integral. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(integral, basic,
print_func<print_dflt>(&integral::do_print).
+ print_func<print_python>(&integral::do_print).
print_func<print_latex>(&integral::do_print_latex))
* Interface to GiNaC's symbolic integral. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- /dev/null
+/** @file integration_kernel.cpp
+ *
+ * Implementation of GiNaC's integration kernels for iterated integrals. */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "integration_kernel.h"
+#include "add.h"
+#include "mul.h"
+#include "operators.h"
+#include "power.h"
+#include "relational.h"
+#include "symbol.h"
+#include "constant.h"
+#include "numeric.h"
+#include "function.h"
+#include "pseries.h"
+#include "utils.h"
+#include "inifcns.h"
+
+#include <iostream>
+#include <stdexcept>
+#include <cln/cln.h>
+
+
+namespace GiNaC {
+
+// anonymous namespace for helper function
+namespace {
+
+/**
+ *
+ * Returns the Kronecker symbol in the case where
+ * a: integer
+ * n: unit or prime number
+ *
+ * If n is an odd prime number, the routine returns the Legendre symbol.
+ *
+ * If n is a unit (e.g n equals 1 or -1) or if n is an even prime number (the only case is n=2)
+ * the routine returns the special values defined below.
+ *
+ * Ref.: Toshitsune Miyake, Modular Forms, Chapter 3.1
+ *
+ */
+numeric kronecker_symbol_prime(const numeric & a, const numeric & n)
+{
+ if ( n == 1 ) {
+ return 1;
+ }
+ else if ( n == -1 ) {
+ if ( a >= 0 ) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
+ }
+ else if ( n == 2 ) {
+ if ( GiNaC::smod(a,8) == 1 ) {
+ return 1;
+ }
+ else if ( GiNaC::smod(a,8) == -1 ) {
+ return 1;
+ }
+ else if ( GiNaC::smod(a,8) == 3 ) {
+ return -1;
+ }
+ else if ( GiNaC::smod(a,8) == -3 ) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ // n is an odd prime number
+ return GiNaC::smod( pow(a,(n-1)/2), n);
+}
+
+/**
+ *
+ * n: positive integer
+ *
+ * a: discriminant of a quadratic field, defines primitive character phi
+ * b: discriminant of a quadratic field, defines primitive character psi
+ * L=|a|: conductor of primitive character phi
+ * M=|b|: conductor of primitive character psi
+ *
+ * k: modular weight
+ *
+ * This function computes
+ * \f[
+ * \sum\limits_{d | n} \psi(d) \phi(n/d) d^{k-1}
+ * \f]
+ *
+ * Ref.: Eq.(5.3.1), William A. Stein, Modular Forms, A computational Approach;
+ *
+ * Eq.(32), arXiv:1704.08895
+ *
+ */
+numeric divisor_function(const numeric & n, const numeric & a, const numeric & b, const numeric & k)
+{
+ ex res = 0;
+
+ for (numeric i1=1; i1<=n; i1++) {
+ if ( irem(n,i1) == 0 ) {
+ numeric ratio = n/i1;
+ res += primitive_dirichlet_character(ratio,a) * primitive_dirichlet_character(i1,b) * pow(i1,k-1);
+ }
+ }
+
+ return ex_to<numeric>(res);
+}
+
+/**
+ *
+ * k: modular weight
+ *
+ * a: discriminant of a quadratic field, defines primitive character phi
+ * b: discriminant of a quadratic field, defines primitive character psi
+ * L=|a|: conductor of primitive character phi
+ * M=|b|: conductor of primitive character psi
+ *
+ * This function computes the constant term of the q-expansion of an Eisenstein series.
+ *
+ * The coefficient is given by the equation below eq.(5.3.1) in William A. Stein, Modular Forms, A computational Approach;
+ *
+ * or by eq.(33), arXiv:1704.08895
+ *
+ */
+numeric coefficient_a0(const numeric & k, const numeric & a, const numeric & b)
+{
+ ex conductor = abs(a);
+
+ numeric a0;
+ if ( conductor == 1 ) {
+ a0 = -numeric(1,2)/k*generalised_Bernoulli_number(k,b);
+ }
+ else {
+ a0 = 0;
+ }
+
+ return a0;
+}
+
+/**
+ *
+ * k: modular weight
+ * q: exp(2 Pi I tau/M)
+ *
+ * a: discriminant of a quadratic field, defines primitive character phi
+ * b: discriminant of a quadratic field, defines primitive character psi
+ * L=|a|: conductor of primitive character phi
+ * M=|b|: conductor of primitive character psi
+ *
+ * N: truncation order
+ *
+ * Returns the q-expansion of an Eisenstein to order N (the q^(N-1)-term is included, q^N is neglected).
+ *
+ * Ref.: Eq.(5.3.1), William A. Stein, Modular Forms, A computational Approach;
+ *
+ * Eq.(32), arXiv:1704.08895
+ *
+ */
+ex eisenstein_series(const numeric & k, const ex & q, const numeric & a, const numeric & b, const numeric & N)
+{
+ ex res = coefficient_a0(k,a,b);
+
+ for (numeric i1=1; i1<N; i1++) {
+ res += divisor_function(i1,a,b,k) * pow(q,i1);
+ }
+
+ return res;
+}
+
+/**
+ *
+ * Returns the q_N-expansion of the Eisenstein series E_{k,a,b}(K tau_N)
+ *
+ */
+ex E_eisenstein_series(const ex & q, const numeric & k, const numeric & N_level, const numeric & a, const numeric & b, const numeric & K, const numeric & N_order)
+{
+ int N_order_int = N_order.to_int();
+
+ ex res = eisenstein_series(k,pow(q,K),a,b,iquo(N_order,K));
+
+ res += Order(pow(q,N_order_int));
+ res = res.series(q,N_order_int);
+
+ return res;
+}
+
+/**
+ *
+ * In weight 2 we have a special case for trivial Dirichlet characters:
+ * Returns the q_N-expansion of the Eisenstein series E_{2,1,1}(tau_N) - K E_{2,1,1}(K tau_N).
+ *
+ */
+ex B_eisenstein_series(const ex & q, const numeric & N_level, const numeric & K, const numeric & N_order)
+{
+ int N_order_int = N_order.to_int();
+
+ ex res = eisenstein_series(2,q,1,1,N_order) - K*eisenstein_series(2,pow(q,K),1,1,iquo(N_order,K));
+
+ res += Order(pow(q,N_order_int));
+ res = res.series(q,N_order_int);
+
+ return res;
+}
+
+/**
+ *
+ * A helper function to expand polynomials in Eisenstein series.
+ *
+ */
+struct subs_q_expansion : public map_function
+{
+ subs_q_expansion(const ex & arg_qbar, int arg_order) : qbar(arg_qbar), order(arg_order)
+ {}
+
+ ex operator()(const ex & e)
+ {
+ if ( is_a<Eisenstein_kernel>(e) || is_a<Eisenstein_h_kernel>(e) ) {
+ return series_to_poly(e.series(qbar,order));
+ }
+ else {
+ return e.map(*this);
+ }
+ }
+
+ ex qbar;
+ int order;
+};
+
+/**
+ *
+ * \f[
+ * Li_{-n}(x), n>=0
+ * \f]
+ *
+ * This is a rational function in x.
+ *
+ * To speed things up, we cache it.
+ *
+ */
+class Li_negative
+{
+ // ctors
+public:
+ Li_negative();
+
+ // non-virtual functions
+public:
+ ex get_symbolic_value(int n, const ex & x_val);
+ ex get_numerical_value(int n, const ex & x_val);
+
+ // member variables :
+protected:
+ static std::vector<ex> cache_vec;
+ static symbol x;
+};
+
+
+Li_negative::Li_negative() {}
+
+ex Li_negative::get_symbolic_value(int n, const ex & x_val)
+{
+ int n_cache = cache_vec.size();
+
+ if ( n >= n_cache ) {
+ for (int j=n_cache; j<=n; j++) {
+ ex f;
+ if ( j == 0 ) {
+ f = x/(1-x);
+ }
+ else {
+ f = normal( x*diff(cache_vec[j-1],x));
+ }
+ cache_vec.push_back( f );
+ }
+ }
+
+ return cache_vec[n].subs(x==x_val);
+}
+
+ex Li_negative::get_numerical_value(int n, const ex & x_val)
+{
+ symbol x_symb("x_symb");
+
+ ex f = this->get_symbolic_value(n,x_symb);
+
+ ex res = f.subs(x_symb==x_val).evalf();
+
+ return res;
+}
+
+// initialise static data members
+std::vector<ex> Li_negative::cache_vec;
+symbol Li_negative::x = symbol("x");
+
+
+} // end of anonymous namespace
+
+/**
+ *
+ * Returns the decomposition of the positive integer n into prime numbers
+ * in the form
+ * lst( lst(p1,...,pr), lst(a1,...,ar) )
+ * such that
+ * n = p1^a1 ... pr^ar.
+ *
+ */
+ex ifactor(const numeric & n)
+{
+ if ( !n.is_pos_integer() ) throw (std::runtime_error("ifactor(): argument not a positive integer"));
+
+ lst p_lst, exp_lst;
+
+ // implementation for small integers
+ numeric n_temp = n;
+ for (numeric p=2; p<=n; p++) {
+ if ( p.info(info_flags::prime) ) {
+ numeric exp_temp = 0;
+ while ( irem(n_temp, p) == 0 ) {
+ n_temp = n_temp/p;
+ exp_temp++;
+ }
+ if ( exp_temp>0 ) {
+ p_lst.append(p);
+ exp_lst.append(exp_temp);
+ }
+ }
+ if ( n_temp == 1 ) break;
+ }
+
+ if ( n_temp != 1 ) throw (std::runtime_error("ifactor(): probabilistic primality test failed"));
+
+ lst res = {p_lst,exp_lst};
+
+ return res;
+}
+
+/**
+ *
+ * Returns true if the integer n is either one or the discriminant of a quadratic number field.
+ *
+ * Returns false otherwise.
+ *
+ * Ref.: Toshitsune Miyake, Modular Forms, Chapter 3.1
+ *
+ */
+bool is_discriminant_of_quadratic_number_field(const numeric & n)
+{
+ if ( n == 0 ) {
+ return false;
+ }
+
+ if ( n == 1 ) {
+ return true;
+ }
+
+ lst prime_factorisation = ex_to<lst>(ifactor(abs(n)));
+ lst p_lst = ex_to<lst>(prime_factorisation.op(0));
+ lst e_lst = ex_to<lst>(prime_factorisation.op(1));
+
+ size_t n_primes = p_lst.nops();
+
+ if ( n_primes > 0 ) {
+ // take the last prime
+ numeric p = ex_to<numeric>(p_lst.op(n_primes-1));
+
+ if ( p.is_odd() ) {
+ if ( e_lst.op(n_primes-1) != 1 ) {
+ return false;
+ }
+
+ numeric pstar = p;
+ if ( mod(p,4) == 3 ) {
+ pstar = -p;
+ }
+ return is_discriminant_of_quadratic_number_field(n/pstar);
+ }
+ }
+ // power of two now
+ if ( (n==-4) || (n==-8) || (n==8) || (n==-32) || (n==32) || (n==-64) || (n==128) ) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ *
+ * Returns the Kronecker symbol
+ * a: integer
+ * n: integer
+ *
+ * This routine defines
+ * kronecker_symbol(1,0) = 1
+ * kronecker_symbol(-1,0) = 1
+ * kronecker_symbol(a,0) = 0, a != 1,-1
+ *
+ * In particular
+ * kronecker_symbol(-1,0) = 1 (in agreement with Sage)
+ *
+ * Ref.: Toshitsune Miyake, Modular Forms, Chapter 3.1
+ *
+ */
+numeric kronecker_symbol(const numeric & a, const numeric & n)
+{
+ // case n=0 first, include kronecker_symbol(0,0)=0
+ if ( n == 0 ) {
+ if ( (a == 1) || (a == -1) ) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ numeric unit = 1;
+ numeric n_pos = n;
+ if ( n_pos<0 ) {
+ unit = -1;
+ n_pos = -n;
+ }
+
+ ex res = kronecker_symbol_prime(a,unit);
+
+ numeric n_odd = n_pos;
+ numeric alpha = 0;
+ while ( n_odd.is_even() ) {
+ alpha++;
+ n_odd = n_odd/2;
+ }
+ if ( alpha>0 ) {
+ res *= pow(kronecker_symbol_prime(a,2),alpha);
+ }
+
+ lst temp_lst = ex_to<lst>(ifactor(n_odd));
+ lst prime_lst = ex_to<lst>(temp_lst.op(0));
+ lst expo_lst = ex_to<lst>(temp_lst.op(1));
+
+ for (auto it_p = prime_lst.begin(), it_e = expo_lst.begin(); it_p != prime_lst.end(); it_p++, it_e++) {
+ res *= pow(kronecker_symbol_prime(a,ex_to<numeric>(*it_p)),ex_to<numeric>(*it_e));
+ }
+
+ return ex_to<numeric>(res);
+}
+
+/**
+ *
+ * Defines a primitive Dirichlet character through the Kronecker symbol.
+ *
+ * n: integer
+ * a: discriminant of a quadratic field
+ * |a|: conductor
+ *
+ * The character takes the values -1,0,1.
+ *
+ */
+numeric primitive_dirichlet_character(const numeric & n, const numeric & a)
+{
+ return kronecker_symbol(a,n);
+}
+
+/**
+ *
+ * Defines a Dirichlet character through the Kronecker symbol.
+ *
+ * n: integer
+ * a: discriminant of a quadratic field
+ * |a|: conductor
+ * N: modulus, needs to be multiple of |a|
+ *
+ * The character takes the values -1,0,1.
+ *
+ */
+numeric dirichlet_character(const numeric & n, const numeric & a, const numeric & N)
+{
+ if ( gcd(n,N) == 1 ) {
+ return primitive_dirichlet_character(n,a);
+ }
+
+ return 0;
+}
+
+/**
+ *
+ * The generalised Bernoulli number.
+ *
+ * k: index / modular weight
+ *
+ * b: discriminant of a quadratic field, defines primitive character psi
+ * M=|b|: conductor of primitive character psi
+ *
+ * The generalised Bernoulli number is computed from the series expansion of the generating function.
+ * The generating function is given in eq.(34), arXiv:1704.08895
+ *
+ */
+numeric generalised_Bernoulli_number(const numeric & k, const numeric & b)
+{
+ int k_int = k.to_int();
+
+ symbol x("x");
+
+ numeric conductor = abs(b);
+
+ ex gen_fct = 0;
+ for (numeric i1=1; i1<=conductor; i1++) {
+ gen_fct += primitive_dirichlet_character(i1,b) * x*exp(i1*x)/(exp(conductor*x)-1);
+ }
+
+ gen_fct = series_to_poly(gen_fct.series(x,k_int+1));
+
+ ex B = factorial(k) * gen_fct.coeff(x,k_int);
+
+ return ex_to<numeric>(B);
+}
+
+/**
+ *
+ * The Bernoulli polynomials
+ *
+ */
+ex Bernoulli_polynomial(const numeric & k, const ex & x)
+{
+ int k_int = k.to_int();
+
+ symbol t("t");
+
+ ex gen_fct = t*exp(x*t)/(exp(t)-1);
+
+ gen_fct = series_to_poly(gen_fct.series(t,k_int+1));
+
+ ex B = factorial(k) * gen_fct.coeff(t,k_int);
+
+ return B;
+}
+
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(integration_kernel, basic,
+ print_func<print_context>(&integration_kernel::do_print))
+
+integration_kernel::integration_kernel() : inherited(), cache_step_size(100), series_vec()
+{
+}
+
+int integration_kernel::compare_same_type(const basic &other) const
+{
+ return 0;
+}
+
+ex integration_kernel::series(const relational & r, int order, unsigned options) const
+{
+ if ( r.rhs() != 0 ) {
+ throw (std::runtime_error("integration_kernel::series: non-zero expansion point not implemented"));
+ }
+
+ return Laurent_series(r.lhs(),order);
+}
+
+/**
+ *
+ * This routine returns true, if the integration kernel has a trailing zero.
+ *
+ */
+bool integration_kernel::has_trailing_zero(void) const
+{
+ if ( cln::zerop( series_coeff(0) ) ) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ *
+ * This routine returns true, if the integration kernel can be evaluated numerically.
+ *
+ */
+bool integration_kernel::is_numeric(void) const
+{
+ return true;
+}
+
+/**
+ *
+ * Subclasses have either to implement series_coeff_impl
+ * or the two methods Laurent_series and uses_Laurent_series.
+ *
+ * The method series_coeff_impl can be used, if a single coefficient can be computed
+ * independently of the others.
+ *
+ * The method Laurent_series can be used, if it is more efficient to compute a Laurent series
+ * in one shot and to determine a range of coefficients from this Laurent series.
+ *
+ */
+cln::cl_N integration_kernel::series_coeff(int i) const
+{
+ int n_vec = series_vec.size();
+
+ if ( i >= n_vec ) {
+ int N = cache_step_size*(i/cache_step_size+1);
+
+ if ( uses_Laurent_series() ) {
+ symbol x("x");
+ // series_vec[0] gives coefficient of 1/z, series_vec[N-1] coefficient of z^(N-2),
+ // thus expansion up to order (N-1) is required
+ ex temp = Laurent_series(x, N-1);
+ for (int j=n_vec; j<N; j++) {
+ series_vec.push_back( ex_to<numeric>(temp.coeff(x,j-1).evalf()).to_cl_N() );
+ }
+ }
+ else {
+ for (int j=n_vec; j<N; j++) {
+ series_vec.push_back( series_coeff_impl(j) );
+ }
+ }
+ }
+
+ return series_vec[i];
+}
+
+/**
+ *
+ * For \f$ \omega = d\lambda \f$ only the coefficient of \f$ \lambda^0 \f$ is non-zero.
+ *
+ * The i-th coefficient corresponds to the power \f$ \lambda^{i-1} \f$.
+ *
+ */
+cln::cl_N integration_kernel::series_coeff_impl(int i) const
+{
+ if ( i == 1 ) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ *
+ * Returns the Laurent series, starting possibly with the pole term.
+ * Neglected terms are of order \f$ O(x^order) \f$.
+ *
+ */
+ex integration_kernel::Laurent_series(const ex & x, int order) const
+{
+ ex res = 0;
+ for (int n=-1; n<order; n++) {
+ res += numeric(series_coeff(n+1)) * pow(x,n);
+ }
+ res += Order(pow(x,order));
+ res = res.series(x,order);
+
+ return res;
+}
+
+/**
+ *
+ * Evaluates the integrand at lambda.
+ *
+ */
+ex integration_kernel::get_numerical_value(const ex & lambda, int N_trunc) const
+{
+ return get_numerical_value_impl(lambda, 1, 0, N_trunc);
+}
+
+/**
+ *
+ * Returns true, if the coefficients are computed from the Laurent series
+ * (in which case the method Laurent_series needs to be implemented).
+ *
+ * Returns false if this is not the case
+ * (and the class has an implementation of series_coeff_impl).
+ *
+ */
+bool integration_kernel::uses_Laurent_series() const
+{
+ return false;
+}
+
+/**
+ *
+ * Returns the current size of the cache.
+ *
+ */
+size_t integration_kernel::get_cache_size(void) const
+{
+ return series_vec.size();
+}
+
+/**
+ *
+ * Sets the step size by which the cache is increased.
+ *
+ */
+void integration_kernel::set_cache_step(int cache_steps) const
+{
+ cache_step_size = cache_steps;
+}
+
+/**
+ *
+ * Wrapper around series_coeff(i), converts cl_N to numeric.
+ *
+ */
+ex integration_kernel::get_series_coeff(int i) const
+{
+ return numeric(series_coeff(i));
+}
+
+/**
+ *
+ * The actual implementation for computing a numerical value for the integrand.
+ *
+ */
+ex integration_kernel::get_numerical_value_impl(const ex & lambda, const ex & pre, int shift, int N_trunc) const
+{
+ cln::cl_N lambda_cln = ex_to<numeric>(lambda.evalf()).to_cl_N();
+ cln::cl_N pre_cln = ex_to<numeric>(pre.evalf()).to_cl_N();
+
+ cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
+
+ cln::cl_N res = 0;
+ cln::cl_N resbuf;
+ cln::cl_N subexpr;
+
+ if ( N_trunc == 0 ) {
+ // sum until precision is reached
+ bool flag_accidental_zero = false;
+
+ int N = 0;
+
+ do {
+ resbuf = res;
+
+ subexpr = series_coeff(N);
+
+ res += pre_cln * subexpr * cln::expt(lambda_cln,N-1+shift);
+
+ flag_accidental_zero = cln::zerop(subexpr);
+
+ N++;
+ } while ( (res != resbuf) || flag_accidental_zero );
+ }
+ else {
+ // N_trunc > 0, sum up the first N_trunc terms
+ for (int N=0; N<N_trunc; N++) {
+ subexpr = series_coeff(N);
+
+ res += pre_cln * subexpr * cln::expt(lambda_cln,N-1+shift);
+ }
+ }
+
+ return numeric(res);
+}
+
+void integration_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "integration_kernel()";
+}
+
+GINAC_BIND_UNARCHIVER(integration_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(basic_log_kernel, integration_kernel,
+ print_func<print_context>(&basic_log_kernel::do_print))
+
+basic_log_kernel::basic_log_kernel() : inherited()
+{
+}
+
+int basic_log_kernel::compare_same_type(const basic &other) const
+{
+ return 0;
+}
+
+cln::cl_N basic_log_kernel::series_coeff_impl(int i) const
+{
+ if ( i == 0 ) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void basic_log_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "basic_log_kernel()";
+}
+
+GINAC_BIND_UNARCHIVER(basic_log_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(multiple_polylog_kernel, integration_kernel,
+ print_func<print_context>(&multiple_polylog_kernel::do_print))
+
+multiple_polylog_kernel::multiple_polylog_kernel() : inherited(), z(_ex1)
+{
+}
+
+multiple_polylog_kernel::multiple_polylog_kernel(const ex & arg_z) : inherited(), z(arg_z)
+{
+}
+
+int multiple_polylog_kernel::compare_same_type(const basic &other) const
+{
+ const multiple_polylog_kernel &o = static_cast<const multiple_polylog_kernel &>(other);
+
+ return z.compare(o.z);
+}
+
+size_t multiple_polylog_kernel::nops() const
+{
+ return 1;
+}
+
+ex multiple_polylog_kernel::op(size_t i) const
+{
+ if ( i != 0 ) {
+ throw(std::range_error("multiple_polylog_kernel::op(): out of range"));
+ }
+
+ return z;
+}
+
+ex & multiple_polylog_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ if ( i != 0 ) {
+ throw(std::range_error("multiple_polylog_kernel::let_op(): out of range"));
+ }
+
+ return z;
+}
+
+bool multiple_polylog_kernel::is_numeric(void) const
+{
+ return z.evalf().info(info_flags::numeric);
+}
+
+cln::cl_N multiple_polylog_kernel::series_coeff_impl(int i) const
+{
+ if ( i == 0 ) {
+ return 0;
+ }
+
+ return -cln::expt(ex_to<numeric>(z.evalf()).to_cl_N(),-i);
+}
+
+void multiple_polylog_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "multiple_polylog_kernel(";
+ z.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(multiple_polylog_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(ELi_kernel, integration_kernel,
+ print_func<print_context>(&ELi_kernel::do_print))
+
+ELi_kernel::ELi_kernel() : inherited(), n(_ex0), m(_ex0), x(_ex0), y(_ex0)
+{
+}
+
+ELi_kernel::ELi_kernel(const ex & arg_n, const ex & arg_m, const ex & arg_x, const ex & arg_y) : inherited(), n(arg_n), m(arg_m), x(arg_x), y(arg_y)
+{
+}
+
+int ELi_kernel::compare_same_type(const basic &other) const
+{
+ const ELi_kernel &o = static_cast<const ELi_kernel &>(other);
+ int cmpval;
+
+ cmpval = n.compare(o.n);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = m.compare(o.m);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = x.compare(o.x);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ return y.compare(o.y);
+}
+
+size_t ELi_kernel::nops() const
+{
+ return 4;
+}
+
+ex ELi_kernel::op(size_t i) const
+{
+ switch (i) {
+ case 0:
+ return n;
+ case 1:
+ return m;
+ case 2:
+ return x;
+ case 3:
+ return y;
+ default:
+ throw (std::out_of_range("ELi_kernel::op() out of range"));
+ }
+}
+
+ex & ELi_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ switch (i) {
+ case 0:
+ return n;
+ case 1:
+ return m;
+ case 2:
+ return x;
+ case 3:
+ return y;
+ default:
+ throw (std::out_of_range("ELi_kernel::let_op() out of range"));
+ }
+}
+
+bool ELi_kernel::is_numeric(void) const
+{
+ return (n.info(info_flags::nonnegint) && m.info(info_flags::numeric) && x.evalf().info(info_flags::numeric) && y.evalf().info(info_flags::numeric));
+}
+
+cln::cl_N ELi_kernel::series_coeff_impl(int i) const
+{
+ if ( i == 0 ) {
+ return 0;
+ }
+
+ int n_int = ex_to<numeric>(n).to_int();
+ int m_int = ex_to<numeric>(m).to_int();
+
+ cln::cl_N x_cln = ex_to<numeric>(x.evalf()).to_cl_N();
+ cln::cl_N y_cln = ex_to<numeric>(y.evalf()).to_cl_N();
+
+ cln::cl_N res_cln = 0;
+
+ for (int j=1; j<=i; j++) {
+ if ( (i % j) == 0 ) {
+ int k = i/j;
+
+ res_cln += cln::expt(x_cln,j)/cln::expt(cln::cl_I(j),n_int) * cln::expt(y_cln,k)/cln::expt(cln::cl_I(k),m_int);
+ }
+ }
+
+ return res_cln;
+}
+
+/**
+ *
+ * Returns the value of ELi_{n,m}(x,y,qbar)
+ *
+ */
+ex ELi_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+ return get_numerical_value_impl(qbar, 1, 1, N_trunc);
+}
+
+void ELi_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "ELi_kernel(";
+ n.print(c);
+ c.s << ",";
+ m.print(c);
+ c.s << ",";
+ x.print(c);
+ c.s << ",";
+ y.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(ELi_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Ebar_kernel, integration_kernel,
+ print_func<print_context>(&Ebar_kernel::do_print))
+
+Ebar_kernel::Ebar_kernel() : inherited(), n(_ex0), m(_ex0), x(_ex0), y(_ex0)
+{
+}
+
+Ebar_kernel::Ebar_kernel(const ex & arg_n, const ex & arg_m, const ex & arg_x, const ex & arg_y) : inherited(), n(arg_n), m(arg_m), x(arg_x), y(arg_y)
+{
+}
+
+int Ebar_kernel::compare_same_type(const basic &other) const
+{
+ const Ebar_kernel &o = static_cast<const Ebar_kernel &>(other);
+ int cmpval;
+
+ cmpval = n.compare(o.n);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = m.compare(o.m);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = x.compare(o.x);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ return y.compare(o.y);
+}
+
+size_t Ebar_kernel::nops() const
+{
+ return 4;
+}
+
+ex Ebar_kernel::op(size_t i) const
+{
+ switch (i) {
+ case 0:
+ return n;
+ case 1:
+ return m;
+ case 2:
+ return x;
+ case 3:
+ return y;
+ default:
+ throw (std::out_of_range("Ebar_kernel::op() out of range"));
+ }
+}
+
+ex & Ebar_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ switch (i) {
+ case 0:
+ return n;
+ case 1:
+ return m;
+ case 2:
+ return x;
+ case 3:
+ return y;
+ default:
+ throw (std::out_of_range("Ebar_kernel::let_op() out of range"));
+ }
+}
+
+bool Ebar_kernel::is_numeric(void) const
+{
+ return (n.info(info_flags::nonnegint) && m.info(info_flags::numeric) && x.evalf().info(info_flags::numeric) && y.evalf().info(info_flags::numeric));
+}
+
+cln::cl_N Ebar_kernel::series_coeff_impl(int i) const
+{
+ if ( i == 0 ) {
+ return 0;
+ }
+
+ int n_int = ex_to<numeric>(n).to_int();
+ int m_int = ex_to<numeric>(m).to_int();
+
+ cln::cl_N x_cln = ex_to<numeric>(x.evalf()).to_cl_N();
+ cln::cl_N y_cln = ex_to<numeric>(y.evalf()).to_cl_N();
+
+ cln::cl_N res_cln = 0;
+
+ for (int j=1; j<=i; j++) {
+ if ( (i % j) == 0 ) {
+ int k = i/j;
+
+ res_cln += (cln::expt(x_cln,j)*cln::expt(y_cln,k)-cln::expt(cln::cl_I(-1),n_int+m_int)*cln::expt(x_cln,-j)*cln::expt(y_cln,-k))/cln::expt(cln::cl_I(j),n_int)/cln::expt(cln::cl_I(k),m_int);
+ }
+ }
+
+ return res_cln;
+}
+
+/**
+ *
+ * Returns the value of Ebar_{n,m}(x,y,qbar)
+ *
+ */
+ex Ebar_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+ return get_numerical_value_impl(qbar, 1, 1, N_trunc);
+}
+
+void Ebar_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "Ebar_kernel(";
+ n.print(c);
+ c.s << ",";
+ m.print(c);
+ c.s << ",";
+ x.print(c);
+ c.s << ",";
+ y.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Ebar_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Kronecker_dtau_kernel, integration_kernel,
+ print_func<print_context>(&Kronecker_dtau_kernel::do_print))
+
+Kronecker_dtau_kernel::Kronecker_dtau_kernel() : inherited(), n(_ex0), z(_ex0), K(_ex1), C_norm(_ex1)
+{
+}
+
+Kronecker_dtau_kernel::Kronecker_dtau_kernel(const ex & arg_n, const ex & arg_z, const ex & arg_K, const ex & arg_C_norm) : inherited(), n(arg_n), z(arg_z), K(arg_K), C_norm(arg_C_norm)
+{
+}
+
+int Kronecker_dtau_kernel::compare_same_type(const basic &other) const
+{
+ const Kronecker_dtau_kernel &o = static_cast<const Kronecker_dtau_kernel &>(other);
+ int cmpval;
+
+ cmpval = n.compare(o.n);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = z.compare(o.z);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = K.compare(o.K);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ return C_norm.compare(o.C_norm);
+}
+
+size_t Kronecker_dtau_kernel::nops() const
+{
+ return 4;
+}
+
+ex Kronecker_dtau_kernel::op(size_t i) const
+{
+ switch (i) {
+ case 0:
+ return n;
+ case 1:
+ return z;
+ case 2:
+ return K;
+ case 3:
+ return C_norm;
+ default:
+ throw (std::out_of_range("Kronecker_dtau_kernel::op() out of range"));
+ }
+}
+
+ex & Kronecker_dtau_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ switch (i) {
+ case 0:
+ return n;
+ case 1:
+ return z;
+ case 2:
+ return K;
+ case 3:
+ return C_norm;
+ default:
+ throw (std::out_of_range("Kronecker_dtau_kernel::let_op() out of range"));
+ }
+}
+
+bool Kronecker_dtau_kernel::is_numeric(void) const
+{
+ return (n.info(info_flags::nonnegint) && z.evalf().info(info_flags::numeric) && K.info(info_flags::posint) && C_norm.evalf().info(info_flags::numeric));
+}
+
+cln::cl_N Kronecker_dtau_kernel::series_coeff_impl(int i) const
+{
+ numeric n_num = ex_to<numeric>(n);
+ int n_int = n_num.to_int();
+
+ // case n=0
+ if ( n_num == 0 ) {
+ if ( i == 0 ) {
+ ex res = -C_norm*K;
+
+ return ex_to<numeric>(res.evalf()).to_cl_N();
+ }
+
+ return 0;
+ }
+
+ // case n=1
+ if ( n_num == 1 ) {
+ return 0;
+ }
+
+ // case n>1
+ if ( i == 0 ) {
+ ex res = C_norm*K / factorial(n_num-2) * bernoulli(n_num)/n_num;
+
+ return ex_to<numeric>(res.evalf()).to_cl_N();
+ }
+
+ // n>1, i>0
+
+ // if K>1 the variable i needs to be a multiple of K
+ int K_int = ex_to<numeric>(K).to_int();
+
+ if ( (i % K_int) != 0 ) {
+ return 0;
+ }
+ int i_local = i/K_int;
+
+ ex w = exp(ex_to<numeric>((2*Pi*I*z).evalf()));
+ cln::cl_N w_cln = ex_to<numeric>(w).to_cl_N();
+ cln::cl_N res_cln = 0;
+ for (int j=1; j<=i_local; j++) {
+ if ( (i_local % j) == 0 ) {
+ res_cln += (cln::expt(w_cln,j)+cln::expt(cln::cl_I(-1),n_int)*cln::expt(w_cln,-j)) * cln::expt(cln::cl_I(i_local/j),n_int-1);
+ }
+ }
+ ex pre = -C_norm*K/factorial(n_num-2);
+
+ return ex_to<numeric>(pre.evalf()).to_cl_N() * res_cln;
+}
+
+/**
+ *
+ * Returns the value of the g^(n)(z,K*tau), where tau is given by qbar.
+ *
+ */
+ex Kronecker_dtau_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+ numeric n_num = ex_to<numeric>(n);
+
+ if ( n_num == 0 ) {
+ return 1;
+ }
+
+ // use the direct formula here
+ if ( n_num == 1 ) {
+ ex wbar = exp(ex_to<numeric>((2*Pi*I*z).evalf()));
+ ex res = -2*Pi*I*( numeric(1,2)*(1+wbar)/(1-wbar) + Ebar_kernel(0,0,wbar,1).get_numerical_value(pow(qbar,K),N_trunc));
+
+ return ex_to<numeric>(res.evalf());
+ }
+
+ ex pre = pow(2*Pi*I,n_num)/C_norm/K/(n_num-1);
+
+ return get_numerical_value_impl(qbar, pre, 1, N_trunc);
+}
+
+void Kronecker_dtau_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "Kronecker_dtau_kernel(";
+ n.print(c);
+ c.s << ",";
+ z.print(c);
+ c.s << ",";
+ K.print(c);
+ c.s << ",";
+ C_norm.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Kronecker_dtau_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Kronecker_dz_kernel, integration_kernel,
+ print_func<print_context>(&Kronecker_dz_kernel::do_print))
+
+Kronecker_dz_kernel::Kronecker_dz_kernel() : inherited(), n(_ex0), z_j(_ex0), tau(_ex0), K(_ex1), C_norm(_ex1)
+{
+}
+
+Kronecker_dz_kernel::Kronecker_dz_kernel(const ex & arg_n, const ex & arg_z_j, const ex & arg_tau, const ex & arg_K, const ex & arg_C_norm) : inherited(), n(arg_n), z_j(arg_z_j), tau(arg_tau), K(arg_K), C_norm(arg_C_norm)
+{
+}
+
+int Kronecker_dz_kernel::compare_same_type(const basic &other) const
+{
+ const Kronecker_dz_kernel &o = static_cast<const Kronecker_dz_kernel &>(other);
+ int cmpval;
+
+ cmpval = n.compare(o.n);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = z_j.compare(o.z_j);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = tau.compare(o.tau);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = K.compare(o.K);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ return C_norm.compare(o.C_norm);
+}
+
+size_t Kronecker_dz_kernel::nops() const
+{
+ return 5;
+}
+
+ex Kronecker_dz_kernel::op(size_t i) const
+{
+ switch (i) {
+ case 0:
+ return n;
+ case 1:
+ return z_j;
+ case 2:
+ return tau;
+ case 3:
+ return K;
+ case 4:
+ return C_norm;
+ default:
+ throw (std::out_of_range("Kronecker_dz_kernel::op() out of range"));
+ }
+}
+
+ex & Kronecker_dz_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ switch (i) {
+ case 0:
+ return n;
+ case 1:
+ return z_j;
+ case 2:
+ return tau;
+ case 3:
+ return K;
+ case 4:
+ return C_norm;
+ default:
+ throw (std::out_of_range("Kronecker_dz_kernel::let_op() out of range"));
+ }
+}
+
+bool Kronecker_dz_kernel::is_numeric(void) const
+{
+ return (n.info(info_flags::nonnegint) && z_j.evalf().info(info_flags::numeric) && tau.evalf().info(info_flags::numeric) && K.info(info_flags::posint) && C_norm.evalf().info(info_flags::numeric));
+}
+
+cln::cl_N Kronecker_dz_kernel::series_coeff_impl(int i) const
+{
+ numeric n_num = ex_to<numeric>(n);
+ int n_int = n_num.to_int();
+
+ ex w_j_inv = exp(ex_to<numeric>((-2*Pi*I*z_j).evalf()));
+ cln::cl_N w_j_inv_cln = ex_to<numeric>(w_j_inv).to_cl_N();
+
+ ex qbar = exp(ex_to<numeric>((2*Pi*I*K*tau).evalf()));
+
+ // case n=0
+ if ( n_num == 0 ) {
+ return 0;
+ }
+
+ // case n=1
+ if ( n_num == 1 ) {
+ if ( i == 1 ) {
+ return ex_to<numeric>((C_norm * 2*Pi*I).evalf()).to_cl_N();
+ }
+
+ return 0;
+ }
+
+ // case n=2
+ if ( n_num == 2 ) {
+ if ( ex_to<numeric>(z_j.evalf()).is_zero() ) {
+ if ( i == 0 ) {
+ return ex_to<numeric>((C_norm).evalf()).to_cl_N();
+ }
+ else if ( i == 1 ) {
+ return 0;
+ }
+ else {
+ ex res = -bernoulli(i)/numeric(i);
+ if ( numeric(i).is_even() ) {
+ Ebar_kernel Ebar = Ebar_kernel( 1-i, 0, numeric(1), numeric(1) );
+ res += Ebar.get_numerical_value(qbar);
+ }
+
+ res *= -pow(2*Pi*I,i)*C_norm/factorial(i-1);
+
+ return ex_to<numeric>(res.evalf()).to_cl_N();
+ }
+ }
+ else {
+ // z_j is not zero
+ if ( i == 0 ) {
+ return 0;
+ }
+ else {
+ Li_negative my_Li_negative;
+
+ ex res = 0;
+ if ( i == 1 ) {
+ res = numeric(1,2);
+ }
+
+ Ebar_kernel Ebar = Ebar_kernel( 1-i, 0, w_j_inv, numeric(1) );
+
+ res += my_Li_negative.get_numerical_value(i-1,w_j_inv) + Ebar.get_numerical_value(qbar);
+
+ res *= -pow(2*Pi*I,i)*C_norm/factorial(i-1);
+
+ return ex_to<numeric>(res.evalf()).to_cl_N();
+ }
+ }
+ }
+
+ // case n>2
+ ex res = 0;
+ if ( i == 1 ) {
+ res += - bernoulli(n_num-1)/(n_num-1);
+ }
+ if ( i > 0 ) {
+ if ( ex_to<numeric>(z_j.evalf()).is_zero() ) {
+ if ( (numeric(i)+n_num).is_even() ) {
+ Ebar_kernel Ebar = Ebar_kernel( 1-i, 2-n_num, numeric(1), numeric(1) );
+
+ res += pow(2*Pi*I,i-1)/factorial(i-1) * Ebar.get_numerical_value(qbar);
+ }
+ }
+ else {
+ // z_j is not zero
+ Ebar_kernel Ebar = Ebar_kernel( 1-i, 2-n_num, w_j_inv, numeric(1) );
+
+ res += pow(2*Pi*I,i-1)/factorial(i-1) * Ebar.get_numerical_value(qbar);
+ }
+ }
+
+ res *= - C_norm * 2*Pi*I/factorial(n_num-2);
+
+ return ex_to<numeric>(res.evalf()).to_cl_N();
+}
+
+/**
+ *
+ * Returns the value of the g^(n-1)(z-z_j,K*tau).
+ *
+ */
+ex Kronecker_dz_kernel::get_numerical_value(const ex & z, int N_trunc) const
+{
+ numeric n_num = ex_to<numeric>(n);
+
+ if ( n_num == 1 ) {
+ return 1;
+ }
+
+ ex pre = pow(2*Pi*I,n-2)/C_norm;
+
+ return get_numerical_value_impl(z, pre, 0, N_trunc);
+}
+
+void Kronecker_dz_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "Kronecker_dz_kernel(";
+ n.print(c);
+ c.s << ",";
+ z_j.print(c);
+ c.s << ",";
+ tau.print(c);
+ c.s << ",";
+ K.print(c);
+ c.s << ",";
+ C_norm.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Kronecker_dz_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Eisenstein_kernel, integration_kernel,
+ print_func<print_context>(&Eisenstein_kernel::do_print))
+
+Eisenstein_kernel::Eisenstein_kernel() : inherited(), k(_ex0), N(_ex0), a(_ex0), b(_ex0), K(_ex0), C_norm(_ex1)
+{
+}
+
+Eisenstein_kernel::Eisenstein_kernel(const ex & arg_k, const ex & arg_N, const ex & arg_a, const ex & arg_b, const ex & arg_K, const ex & arg_C_norm) : inherited(), k(arg_k), N(arg_N), a(arg_a), b(arg_b), K(arg_K), C_norm(arg_C_norm)
+{
+}
+
+int Eisenstein_kernel::compare_same_type(const basic &other) const
+{
+ const Eisenstein_kernel &o = static_cast<const Eisenstein_kernel &>(other);
+ int cmpval;
+
+ cmpval = k.compare(o.k);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = N.compare(o.N);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = a.compare(o.a);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = b.compare(o.b);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = K.compare(o.K);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ return C_norm.compare(o.C_norm);
+}
+
+/**
+ *
+ * The series method for this class returns the qbar-expansion of the modular form,
+ * without an additional factor of C_norm/qbar.
+ *
+ * This allows for easy use in the class modular_form_kernel.
+ *
+ */
+ex Eisenstein_kernel::series(const relational & r, int order, unsigned options) const
+{
+ if ( r.rhs() != 0 ) {
+ throw (std::runtime_error("integration_kernel::series: non-zero expansion point not implemented"));
+ }
+
+ ex qbar = r.lhs();
+ ex res = q_expansion_modular_form(qbar, order);
+ res = res.series(qbar,order);
+
+ return res;
+}
+
+size_t Eisenstein_kernel::nops() const
+{
+ return 6;
+}
+
+ex Eisenstein_kernel::op(size_t i) const
+{
+ switch (i) {
+ case 0:
+ return k;
+ case 1:
+ return N;
+ case 2:
+ return a;
+ case 3:
+ return b;
+ case 4:
+ return K;
+ case 5:
+ return C_norm;
+ default:
+ throw (std::out_of_range("Eisenstein_kernel::op() out of range"));
+ }
+}
+
+ex & Eisenstein_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ switch (i) {
+ case 0:
+ return k;
+ case 1:
+ return N;
+ case 2:
+ return a;
+ case 3:
+ return b;
+ case 4:
+ return K;
+ case 5:
+ return C_norm;
+ default:
+ throw (std::out_of_range("Eisenstein_kernel::let_op() out of range"));
+ }
+}
+
+bool Eisenstein_kernel::is_numeric(void) const
+{
+ return (k.info(info_flags::nonnegint) && N.info(info_flags::posint) && a.info(info_flags::integer) && b.info(info_flags::integer) && K.info(info_flags::posint) && C_norm.evalf().info(info_flags::numeric));
+}
+
+ex Eisenstein_kernel::Laurent_series(const ex & x, int order) const
+{
+ ex res = C_norm * q_expansion_modular_form(x, order+1)/x;
+ res = res.series(x,order);
+
+ return res;
+}
+
+/**
+ *
+ * Returns the value of the modular form.
+ *
+ */
+ex Eisenstein_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+ ex pre = numeric(1)/C_norm;
+
+ return get_numerical_value_impl(qbar, pre, 1, N_trunc);
+}
+
+bool Eisenstein_kernel::uses_Laurent_series() const
+{
+ return true;
+}
+
+ex Eisenstein_kernel::q_expansion_modular_form(const ex & q, int order) const
+{
+ numeric k_num = ex_to<numeric>(k);
+ numeric N_num = ex_to<numeric>(N);
+ numeric a_num = ex_to<numeric>(a);
+ numeric b_num = ex_to<numeric>(b);
+ numeric K_num = ex_to<numeric>(K);
+
+ if ( (k==2) && (a==1) && (b==1) ) {
+ return B_eisenstein_series(q, N_num, K_num, order);
+ }
+
+ return E_eisenstein_series(q, k_num, N_num, a_num, b_num, K_num, order);
+}
+
+void Eisenstein_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "Eisenstein_kernel(";
+ k.print(c);
+ c.s << ",";
+ N.print(c);
+ c.s << ",";
+ a.print(c);
+ c.s << ",";
+ b.print(c);
+ c.s << ",";
+ K.print(c);
+ c.s << ",";
+ C_norm.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Eisenstein_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(Eisenstein_h_kernel, integration_kernel,
+ print_func<print_context>(&Eisenstein_h_kernel::do_print))
+
+Eisenstein_h_kernel::Eisenstein_h_kernel() : inherited(), k(_ex0), N(_ex0), r(_ex0), s(_ex0), C_norm(_ex1)
+{
+}
+
+Eisenstein_h_kernel::Eisenstein_h_kernel(const ex & arg_k, const ex & arg_N, const ex & arg_r, const ex & arg_s, const ex & arg_C_norm) : inherited(), k(arg_k), N(arg_N), r(arg_r), s(arg_s), C_norm(arg_C_norm)
+{
+}
+
+int Eisenstein_h_kernel::compare_same_type(const basic &other) const
+{
+ const Eisenstein_h_kernel &o = static_cast<const Eisenstein_h_kernel &>(other);
+ int cmpval;
+
+ cmpval = k.compare(o.k);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = N.compare(o.N);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = r.compare(o.r);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = s.compare(o.s);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ return C_norm.compare(o.C_norm);
+}
+
+/**
+ *
+ * The series method for this class returns the qbar-expansion of the modular form,
+ * without an additional factor of C_norm/qbar.
+ *
+ * This allows for easy use in the class modular_form_kernel.
+ *
+ */
+ex Eisenstein_h_kernel::series(const relational & r, int order, unsigned options) const
+{
+ if ( r.rhs() != 0 ) {
+ throw (std::runtime_error("integration_kernel::series: non-zero expansion point not implemented"));
+ }
+
+ ex qbar = r.lhs();
+ ex res = q_expansion_modular_form(qbar, order);
+ res = res.series(qbar,order);
+
+ return res;
+}
+
+size_t Eisenstein_h_kernel::nops() const
+{
+ return 5;
+}
+
+ex Eisenstein_h_kernel::op(size_t i) const
+{
+ switch (i) {
+ case 0:
+ return k;
+ case 1:
+ return N;
+ case 2:
+ return r;
+ case 3:
+ return s;
+ case 4:
+ return C_norm;
+ default:
+ throw (std::out_of_range("Eisenstein_h_kernel::op() out of range"));
+ }
+}
+
+ex & Eisenstein_h_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ switch (i) {
+ case 0:
+ return k;
+ case 1:
+ return N;
+ case 2:
+ return r;
+ case 3:
+ return s;
+ case 4:
+ return C_norm;
+ default:
+ throw (std::out_of_range("Eisenstein_h_kernel::let_op() out of range"));
+ }
+}
+
+bool Eisenstein_h_kernel::is_numeric(void) const
+{
+ return (k.info(info_flags::nonnegint) && N.info(info_flags::posint) && r.info(info_flags::integer) && s.info(info_flags::integer) && C_norm.evalf().info(info_flags::numeric));
+}
+
+ex Eisenstein_h_kernel::Laurent_series(const ex & x, int order) const
+{
+ ex res = C_norm * q_expansion_modular_form(x, order+1)/x;
+ res = res.series(x,order);
+
+ return res;
+}
+
+/**
+ *
+ * Returns the value of the modular form.
+ *
+ */
+ex Eisenstein_h_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+ ex pre = numeric(1)/C_norm;
+
+ return get_numerical_value_impl(qbar, pre, 1, N_trunc);
+}
+
+bool Eisenstein_h_kernel::uses_Laurent_series() const
+{
+ return true;
+}
+
+/**
+ *
+ * The constant coefficient in the Fourier expansion.
+ *
+ */
+ex Eisenstein_h_kernel::coefficient_a0(const numeric & k, const numeric & r, const numeric & s, const numeric & N) const
+{
+ if ( k == 1 ) {
+ if ( irem(s,N) != 0 ) {
+ return numeric(1,4) - mod(s,N)/numeric(2)/N;
+ }
+ else if ( (irem(r,N)==0) && (irem(s,N)==0) ) {
+ return 0;
+ }
+ else {
+ return I*numeric(1,4)*cos(Pi*mod(r,N)/N)/sin(Pi*mod(r,N)/N);
+ }
+ }
+
+ // case k > 1
+ return -Bernoulli_polynomial(k,mod(s,N)/N)/numeric(2)/k;
+}
+
+/**
+ *
+ * The higher coefficients in the Fourier expansion.
+ *
+ */
+ex Eisenstein_h_kernel::coefficient_an(const numeric & n, const numeric & k, const numeric & r, const numeric & s, const numeric & N) const
+{
+ ex res = 0;
+
+ for (numeric m=1; m<=n; m++) {
+ if ( irem(n,m) == 0 ) {
+ for (numeric c1=0; c1<N; c1++) {
+ numeric c2 = n/m;
+ res += pow(m,k-1)*exp(2*Pi*I/N*mod(r*c2-(s-m)*c1,N)) - pow(-m,k-1)*exp(2*Pi*I/N*mod(-r*c2+(s+m)*c1,N));
+ }
+ }
+ }
+
+ return res/numeric(2)/pow(N,k);
+}
+
+ex Eisenstein_h_kernel::q_expansion_modular_form(const ex & q, int N_order) const
+{
+ numeric N_order_num = numeric(N_order);
+
+ numeric k_num = ex_to<numeric>(k);
+ numeric r_num = ex_to<numeric>(r);
+ numeric s_num = ex_to<numeric>(s);
+ numeric N_num = ex_to<numeric>(N);
+
+ ex res = coefficient_a0(k_num,r_num,s_num,N_num);
+
+ for (numeric i1=1; i1<N_order_num; i1++) {
+ res += coefficient_an(i1,k_num,r_num,s_num,N_num) * pow(q,i1);
+ }
+
+ res += Order(pow(q,N_order));
+ res = res.series(q,N_order);
+
+ return res;
+}
+
+void Eisenstein_h_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "Eisenstein_h_kernel(";
+ k.print(c);
+ c.s << ",";
+ N.print(c);
+ c.s << ",";
+ r.print(c);
+ c.s << ",";
+ s.print(c);
+ c.s << ",";
+ C_norm.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(Eisenstein_h_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(modular_form_kernel, integration_kernel,
+ print_func<print_context>(&modular_form_kernel::do_print))
+
+modular_form_kernel::modular_form_kernel() : inherited(), k(_ex0), P(_ex0), C_norm(_ex1)
+{
+}
+
+modular_form_kernel::modular_form_kernel(const ex & arg_k, const ex & arg_P, const ex & arg_C_norm) : inherited(), k(arg_k), P(arg_P), C_norm(arg_C_norm)
+{
+}
+
+int modular_form_kernel::compare_same_type(const basic &other) const
+{
+ const modular_form_kernel &o = static_cast<const modular_form_kernel &>(other);
+ int cmpval;
+
+ cmpval = k.compare(o.k);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ cmpval = P.compare(o.P);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ return C_norm.compare(o.C_norm);
+}
+
+/**
+ *
+ * The series method for this class returns the qbar-expansion of the modular form,
+ * without an additional factor of C_norm/qbar.
+ *
+ */
+ex modular_form_kernel::series(const relational & r, int order, unsigned options) const
+{
+ if ( r.rhs() != 0 ) {
+ throw (std::runtime_error("integration_kernel::series: non-zero expansion point not implemented"));
+ }
+
+ ex qbar = r.lhs();
+
+ subs_q_expansion do_subs_q_expansion(qbar, order);
+
+ ex res = do_subs_q_expansion(P).series(qbar,order);
+ res += Order(pow(qbar,order));
+ res = res.series(qbar,order);
+
+ return res;
+}
+
+size_t modular_form_kernel::nops() const
+{
+ return 3;
+}
+
+ex modular_form_kernel::op(size_t i) const
+{
+ switch (i) {
+ case 0:
+ return k;
+ case 1:
+ return P;
+ case 2:
+ return C_norm;
+ default:
+ throw (std::out_of_range("modular_form_kernel::op() out of range"));
+ }
+}
+
+ex & modular_form_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ switch (i) {
+ case 0:
+ return k;
+ case 1:
+ return P;
+ case 2:
+ return C_norm;
+ default:
+ throw (std::out_of_range("modular_form_kernel::let_op() out of range"));
+ }
+}
+
+bool modular_form_kernel::is_numeric(void) const
+{
+ bool flag = (k.info(info_flags::nonnegint) && C_norm.evalf().info(info_flags::numeric));
+ if ( !flag ) {
+ return false;
+ }
+
+ symbol qbar("qbar");
+
+ // test with a random number and random expansion
+ return series_to_poly(q_expansion_modular_form(qbar,18)).subs(qbar==numeric(1,937)).evalf().info(info_flags::numeric);
+}
+
+ex modular_form_kernel::Laurent_series(const ex & qbar, int order) const
+{
+ ex res = series_to_poly(q_expansion_modular_form(qbar,order+1));
+ res = C_norm * res/qbar;
+ res = res.series(qbar,order);
+ return res;
+}
+
+/**
+ *
+ * Returns the value of the modular form.
+ *
+ */
+ex modular_form_kernel::get_numerical_value(const ex & qbar, int N_trunc) const
+{
+ ex pre = numeric(1)/C_norm;
+
+ return get_numerical_value_impl(qbar, pre, 1, N_trunc);
+}
+
+bool modular_form_kernel::uses_Laurent_series() const
+{
+ return true;
+}
+
+ex modular_form_kernel::q_expansion_modular_form(const ex & q, int N_order) const
+{
+ return this->series(q==0,N_order);
+}
+
+void modular_form_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "modular_form_kernel(";
+ k.print(c);
+ c.s << ",";
+ P.print(c);
+ c.s << ",";
+ C_norm.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(modular_form_kernel);
+
+
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(user_defined_kernel, integration_kernel,
+ print_func<print_context>(&user_defined_kernel::do_print))
+
+user_defined_kernel::user_defined_kernel() : inherited(), f(_ex0), x(_ex0)
+{
+}
+
+user_defined_kernel::user_defined_kernel(const ex & arg_f, const ex & arg_x) : inherited(), f(arg_f), x(arg_x)
+{
+}
+
+int user_defined_kernel::compare_same_type(const basic &other) const
+{
+ const user_defined_kernel &o = static_cast<const user_defined_kernel &>(other);
+ int cmpval;
+
+ cmpval = f.compare(o.f);
+ if ( cmpval) {
+ return cmpval;
+ }
+
+ return x.compare(o.x);
+}
+
+size_t user_defined_kernel::nops() const
+{
+ return 2;
+}
+
+ex user_defined_kernel::op(size_t i) const
+{
+ switch (i) {
+ case 0:
+ return f;
+ case 1:
+ return x;
+ default:
+ throw (std::out_of_range("user_defined_kernel::op() out of range"));
+ }
+}
+
+ex & user_defined_kernel::let_op(size_t i)
+{
+ ensure_if_modifiable();
+
+ switch (i) {
+ case 0:
+ return f;
+ case 1:
+ return x;
+ default:
+ throw (std::out_of_range("user_defined_kernel::let_op() out of range"));
+ }
+}
+
+bool user_defined_kernel::is_numeric(void) const
+{
+ // test with a random number
+ return f.subs(x==numeric(1,937)).evalf().info(info_flags::numeric);
+}
+
+ex user_defined_kernel::Laurent_series(const ex & x_up, int order) const
+{
+ ex res = f.series(x,order).subs(x==x_up);
+
+ return res;
+}
+
+bool user_defined_kernel::uses_Laurent_series() const
+{
+ return true;
+}
+
+void user_defined_kernel::do_print(const print_context & c, unsigned level) const
+{
+ c.s << "user_defined_kernel(";
+ f.print(c);
+ c.s << ",";
+ x.print(c);
+ c.s << ")";
+}
+
+GINAC_BIND_UNARCHIVER(user_defined_kernel);
+
+} // namespace GiNaC
--- /dev/null
+/** @file integration_kernel.h
+ *
+ * Interface to GiNaC's integration kernels for iterated integrals. */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GINAC_INTEGRATION_KERNEL_H
+#define GINAC_INTEGRATION_KERNEL_H
+
+#include "basic.h"
+#include "archive.h"
+#include "numeric.h"
+#include "lst.h"
+
+#include <cln/complex.h>
+#include <vector>
+
+namespace GiNaC {
+
+ex ifactor(const numeric & n);
+bool is_discriminant_of_quadratic_number_field(const numeric & n);
+numeric kronecker_symbol(const numeric & a, const numeric & n);
+numeric primitive_dirichlet_character(const numeric & n, const numeric & a);
+numeric dirichlet_character(const numeric & n, const numeric & a, const numeric & N);
+numeric generalised_Bernoulli_number(const numeric & k, const numeric & b);
+ex Bernoulli_polynomial(const numeric & k, const ex & x);
+
+/**
+ *
+ * The base class for integration kernels for iterated integrals.
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega = d\lambda
+ * \f]
+ * The integration variable is a dummy variable and does not need to be specified.
+ *
+ */
+class integration_kernel : public basic
+{
+ GINAC_DECLARE_REGISTERED_CLASS(integration_kernel, basic)
+
+ // ctors
+public:
+
+ // functions overriding virtual functions from base classes
+public:
+ ex series(const relational & r, int order, unsigned options = 0) const override;
+
+protected:
+
+ // new virtual functions which can be overridden by derived classes
+public:
+ virtual bool has_trailing_zero(void) const;
+ virtual bool is_numeric(void) const;
+ virtual ex Laurent_series(const ex & x, int order) const;
+ virtual ex get_numerical_value(const ex & lambda, int N_trunc = 0) const;
+
+protected:
+ virtual bool uses_Laurent_series() const;
+ virtual cln::cl_N series_coeff_impl(int i) const;
+
+ // non-virtual functions
+public:
+ size_t get_cache_size(void) const;
+ void set_cache_step(int cache_steps) const;
+ ex get_series_coeff(int i) const;
+ cln::cl_N series_coeff(int i) const;
+
+protected:
+ ex get_numerical_value_impl(const ex & lambda, const ex & pre, int shift, int N_trunc) const;
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ // cache is increased by steps of cache_step_size
+ mutable int cache_step_size;
+ // cache already computed series coefficients
+ mutable std::vector<cln::cl_N> series_vec;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(integration_kernel);
+
+/**
+ *
+ * The basic integration kernel with a logarithmic singularity at the origin.
+ *
+ * This class represents the differential one-form
+ * \f[
+ * L_0 = \frac{d\lambda}{\lambda}
+ * \f]
+ *
+ */
+class basic_log_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(basic_log_kernel, integration_kernel)
+
+ // ctors
+public:
+
+ // functions overriding virtual functions from base classes
+public:
+
+protected:
+ cln::cl_N series_coeff_impl(int i) const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+
+};
+
+GINAC_DECLARE_UNARCHIVER(basic_log_kernel);
+
+/**
+ *
+ * The integration kernel for multiple polylogarithms.
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega^{\mathrm{mpl}}(z) = \frac{d\lambda}{\lambda-z}
+ * \f]
+ *
+ * For the case \f$ z=0 \f$ the class basic_log_kernel should be used.
+ *
+ */
+class multiple_polylog_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(multiple_polylog_kernel, integration_kernel)
+
+ // ctors
+public:
+ multiple_polylog_kernel(const ex & z);
+
+ // functions overriding virtual functions from base classes
+public:
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+
+protected:
+ cln::cl_N series_coeff_impl(int i) const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex z;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(multiple_polylog_kernel);
+
+/**
+ *
+ * The ELi-kernel.
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega^{\mathrm{ELi}}_{n;m}(x;y) = \mathrm{ELi}_{n;m}(x;y;\bar{q}) \frac{d\bar{q}}{\bar{q}}
+ * \f]
+ *
+ */
+class ELi_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(ELi_kernel, integration_kernel)
+
+ // ctors
+public:
+ ELi_kernel(const ex & n, const ex & m, const ex & x, const ex & y);
+
+ // functions overriding virtual functions from base classes
+public:
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+ ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+ cln::cl_N series_coeff_impl(int i) const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex n;
+ ex m;
+ ex x;
+ ex y;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(ELi_kernel);
+
+/**
+ *
+ * The Ebar-kernel
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega^{\overline{\mathrm{E}}}_{n;m}(x;y) = \overline{\mathrm{E}}_{n;m}(x;y;\bar{q}) \frac{d\bar{q}}{\bar{q}}
+ * \f]
+ *
+ */
+class Ebar_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(Ebar_kernel, integration_kernel)
+
+ // ctors
+public:
+ Ebar_kernel(const ex & n, const ex & m, const ex & x, const ex & y);
+
+ // functions overriding virtual functions from base classes
+public:
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+ ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+ cln::cl_N series_coeff_impl(int i) const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex n;
+ ex m;
+ ex x;
+ ex y;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(Ebar_kernel);
+
+/**
+ *
+ * The kernel corresponding to integrating the Kronecker coefficient function \f$ g^{(n)}(z_j,K \tau) \f$
+ * in \f$ \tau \f$ (or equivalently in \f$ \bar{q} \f$).
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega^{\mathrm{Kronecker},\tau}_{n,K}(z_j) = \frac{C_n K (n-1)}{(2\pi i)^n} g^{(n)}(z_j,K \tau) \frac{d\bar{q}}{\bar{q}}
+ * \f]
+ *
+ */
+class Kronecker_dtau_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(Kronecker_dtau_kernel, integration_kernel)
+
+ // ctors
+public:
+ Kronecker_dtau_kernel(const ex & n, const ex & z, const ex & K = numeric(1), const ex & C_norm = numeric(1));
+
+ // functions overriding virtual functions from base classes
+public:
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+ ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+ cln::cl_N series_coeff_impl(int i) const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex n;
+ ex z;
+ ex K;
+ ex C_norm;
+};
+
+GINAC_DECLARE_UNARCHIVER(Kronecker_dtau_kernel);
+
+
+/**
+ *
+ * The kernel corresponding to integrating the Kronecker coefficient function \f$ g^{(n-1)}(z-z_j, K \tau) \f$
+ * in \f$ z \f$.
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega^{\mathrm{Kronecker},z}_{n,K}(z_j,\tau) = C_n (2\pi i)^{2-n} g^{(n-1)}(z-z_j, K \tau) dz
+ * \f]
+ *
+ */
+class Kronecker_dz_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(Kronecker_dz_kernel, integration_kernel)
+
+ // ctors
+public:
+ Kronecker_dz_kernel(const ex & n, const ex & z_j, const ex & tau, const ex & K = numeric(1), const ex & C_norm = numeric(1));
+
+ // functions overriding virtual functions from base classes
+public:
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+ ex get_numerical_value(const ex & z, int N_trunc = 0) const override;
+
+protected:
+ cln::cl_N series_coeff_impl(int i) const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex n;
+ ex z_j;
+ ex tau;
+ ex K;
+ ex C_norm;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(Kronecker_dz_kernel);
+
+
+/**
+ *
+ * The kernel corresponding to the Eisenstein series \f$ E_{k,N,a,b,K}(\tau) \f$.
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega^{\mathrm{Eisenstein}}_{k,N,a,b,K} = C_k E_{k,N,a,b,K}(\tau) \frac{d\bar{q}_N}{\bar{q}_N}
+ * \f]
+ *
+ * The integers a and b are either one or the discriminant of a quadratic number field.
+ * This class represents Eisenstein series, which can be defined by primitive Dirichlet characters from the Kronecker symbol.
+ * This implies that the characters take the values -1,0,1, i.e. no higher roots of unity occur.
+ * The \f[ \bar{q} \f]-expansion has then rational coefficients.
+ *
+ * Ref.: W. Stein, Modular Forms: A Computational Approach, Chapter 5
+ *
+ */
+class Eisenstein_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(Eisenstein_kernel, integration_kernel)
+
+ // ctors
+public:
+ Eisenstein_kernel(const ex & k, const ex & N, const ex & a, const ex & b, const ex & K, const ex & C_norm = numeric(1));
+
+ // functions overriding virtual functions from base classes
+public:
+ ex series(const relational & r, int order, unsigned options = 0) const override;
+
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+ ex Laurent_series(const ex & x, int order) const override;
+ ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+ bool uses_Laurent_series() const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+ ex q_expansion_modular_form(const ex & q, int order) const;
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex k;
+ ex N;
+ ex a;
+ ex b;
+ ex K;
+ ex C_norm;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(Eisenstein_kernel);
+
+
+/**
+ *
+ * The kernel corresponding to the Eisenstein series \f$ h_{k,N,r,s}(\tau) \f$.
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega^{\mathrm{Eisenstein,h}}_{k,N,r,s} = C_k h_{k,N,r,s}(\tau) \frac{d\bar{q}_N}{\bar{q}_N}
+ * \f]
+ *
+ */
+class Eisenstein_h_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(Eisenstein_h_kernel, integration_kernel)
+
+ // ctors
+public:
+ Eisenstein_h_kernel(const ex & k, const ex & N, const ex & r, const ex & s, const ex & C_norm = numeric(1));
+
+ // functions overriding virtual functions from base classes
+public:
+ ex series(const relational & r, int order, unsigned options = 0) const override;
+
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+ ex Laurent_series(const ex & x, int order) const override;
+ ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+ bool uses_Laurent_series() const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+ ex coefficient_a0(const numeric & k, const numeric & r, const numeric & s, const numeric & N) const;
+ ex coefficient_an(const numeric & n, const numeric & k, const numeric & r, const numeric & s, const numeric & N) const;
+ ex q_expansion_modular_form(const ex & q, int order) const;
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex k;
+ ex N;
+ ex r;
+ ex s;
+ ex C_norm;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(Eisenstein_h_kernel);
+
+
+/**
+ *
+ * A kernel corresponding to a polynomial in Eisenstein series.
+ *
+ * This class represents the differential one-form
+ * \f[
+ * \omega^{\mathrm{modular}}(P_k(\eta^{(1)}_{k_1}, \dots, \eta^{(r)}_{k_r})) = C_k P_k(\eta^{(1)}_{k_1}, \dots, \eta^{(r)}_{k_r}) \frac{d\bar{q}_N}{\bar{q}_N}.
+ * \f]
+ *
+ */
+class modular_form_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(modular_form_kernel, integration_kernel)
+
+ // ctors
+public:
+ modular_form_kernel(const ex & k, const ex & P, const ex & C_norm = numeric(1));
+
+ // functions overriding virtual functions from base classes
+public:
+ ex series(const relational & r, int order, unsigned options = 0) const override;
+
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+ ex Laurent_series(const ex & qbar, int order) const override;
+ ex get_numerical_value(const ex & qbar, int N_trunc = 0) const override;
+
+protected:
+ bool uses_Laurent_series() const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+ ex q_expansion_modular_form(const ex & q, int order) const;
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex k;
+ ex P;
+ ex C_norm;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(modular_form_kernel);
+
+
+/**
+ *
+ * A user-defined integration kernel.
+ * The input is an expression \f$ f \f$, depending on a variable \f$ x \f$.
+ * It is assumed that \f$ f \f$ has a Laurent expansion around \f$ x=0 \f$ and
+ * maximally a simple pole at \f$ x=0 \f$.
+ *
+ */
+class user_defined_kernel : public integration_kernel
+{
+ GINAC_DECLARE_REGISTERED_CLASS(user_defined_kernel, integration_kernel)
+
+ // ctors
+public:
+ user_defined_kernel(const ex & f, const ex & x);
+
+ // functions overriding virtual functions from base classes
+public:
+ size_t nops() const override;
+ ex op(size_t i) const override;
+ ex & let_op(size_t i) override;
+
+ bool is_numeric(void) const override;
+ ex Laurent_series(const ex & x, int order) const override;
+
+protected:
+ bool uses_Laurent_series() const override;
+
+ // new virtual functions which can be overridden by derived classes
+public:
+
+protected:
+
+ // non-virtual functions
+public:
+
+protected:
+ void do_print(const print_context & c, unsigned level) const;
+
+ // friends :
+
+ // member variables :
+
+protected:
+ ex f;
+ ex x;
+
+};
+
+GINAC_DECLARE_UNARCHIVER(user_defined_kernel);
+
+} // namespace GiNaC
+
+#endif // ndef GINAC_INTEGRATION_KERNEL_H
* Implementation of GiNaC's lst. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
return inherited::info(inf);
}
+template bool container<std::list>::info(unsigned) const;
GINAC_BIND_UNARCHIVER(lst);
} // namespace GiNaC
* Definition of GiNaC's lst. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
typedef container<std::list> lst;
+/** Declaration of container::reg_info for lst. */
+#ifndef _MSC_VER // workaround error C2766: explicit specialization; 'reg_info' has already been defined
+template<> registered_class_info lst::reg_info;
+#endif
+
/** Specialization of container::get_default_flags() for lst. */
template<> inline unsigned lst::get_default_flags() { return status_flags::not_shareable; }
// defined in lst.cpp
template<> bool lst::info(unsigned inf) const;
+extern template bool container<std::list>::info(unsigned) const;
GINAC_DECLARE_UNARCHIVER(lst);
} // namespace GiNaC
* Implementation of symbolic matrices */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to symbolic matrices */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
namespace GiNaC {
-/** Helper template to allow initialization of matrices via an overloaded
- * comma operator (idea stolen from Blitz++). */
-template <typename T, typename It>
-class matrix_init {
-public:
- matrix_init(It i) : iter(i) {}
-
- matrix_init<T, It> operator,(const T & x)
- {
- *iter = x;
- return matrix_init<T, It>(++iter);
- }
-
- // The following specializations produce much tighter code than the
- // general case above
-
- matrix_init<T, It> operator,(int x)
- {
- *iter = T(x);
- return matrix_init<T, It>(++iter);
- }
-
- matrix_init<T, It> operator,(unsigned int x)
- {
- *iter = T(x);
- return matrix_init<T, It>(++iter);
- }
-
- matrix_init<T, It> operator,(long x)
- {
- *iter = T(x);
- return matrix_init<T, It>(++iter);
- }
-
- matrix_init<T, It> operator,(unsigned long x)
- {
- *iter = T(x);
- return matrix_init<T, It>(++iter);
- }
-
- matrix_init<T, It> operator,(double x)
- {
- *iter = T(x);
- return matrix_init<T, It>(++iter);
- }
-
- matrix_init<T, It> operator,(const symbol & x)
- {
- *iter = T(x);
- return matrix_init<T, It>(++iter);
- }
-
-private:
- matrix_init();
- It iter;
-};
-
-
/** Symbolic matrices. */
class matrix : public basic
{
matrix(unsigned r, unsigned c, const lst & l);
matrix(std::initializer_list<std::initializer_list<ex>> l);
- matrix_init<ex, exvector::iterator> operator=(const ex & x) attribute_deprecated;
protected:
matrix(unsigned r, unsigned c, const exvector & m2);
matrix(unsigned r, unsigned c, exvector && m2);
};
GINAC_DECLARE_UNARCHIVER(matrix);
-// First step of initialization of matrix with a comma-separated sequence
-// of expressions. Subsequent steps are handled by matrix_init<>::operator,().
-inline matrix_init<ex, exvector::iterator> matrix::operator=(const ex & x)
-{
- m[0] = x;
- return matrix_init<ex, exvector::iterator>(++m.begin());
-}
-
// wrapper functions around member functions
inline size_t nops(const matrix & m)
* Implementation of GiNaC's products of expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's products of expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
ex imag_part() const override;
ex evalm() const override;
ex series(const relational & s, int order, unsigned options = 0) const override;
- ex normal(exmap & repl, exmap & rev_lookup) const override;
+ ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
numeric integer_content() const override;
ex smod(const numeric &xi) const override;
numeric max_coefficient() const override;
* Implementation of GiNaC's non-commutative products of expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's non-commutative products of expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* computation, square-free factorization and rational function normalization. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* @param cb pointer to expression that will receive the cofactor of b, or nullptr
* @param check_args check whether a and b are polynomials with rational
* coefficients (defaults to "true")
+ * @param options see GiNaC::gcd_options
* @return the GCD as a new expression */
ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args, unsigned options)
{
ex z = w.diff(x);
ex g = gcd(w, z);
if (g.is_zero()) {
- return epvector{};
+ // manifest zero or hidden zero
+ return {};
}
if (g.is_equal(_ex1)) {
- return epvector{expair(a, _ex1)};
+ // w(x) and w'(x) share no factors: w(x) is square-free
+ return {expair(a, _ex1)};
}
- epvector results;
- ex exponent = _ex0;
+
+ epvector factors;
+ ex i = 0; // exponent
do {
w = quo(w, g, x);
if (w.is_zero()) {
- return results;
+ // hidden zero
+ break;
}
z = quo(z, g, x) - w.diff(x);
- exponent = exponent + 1;
+ i += 1;
if (w.is_equal(x)) {
// shortcut for x^n with n ∈ ℕ
- exponent += quo(z, w.diff(x), x);
- results.push_back(expair(w, exponent));
+ i += quo(z, w.diff(x), x);
+ factors.push_back(expair(w, i));
break;
}
g = gcd(w, z);
if (!g.is_equal(_ex1)) {
- results.push_back(expair(g, exponent));
+ factors.push_back(expair(g, i));
}
} while (!z.is_zero());
+
+ // correct for lost factor
+ // (being based on GCDs, Yun's algorithm only finds factors up to a unit)
+ const ex lost_factor = quo(a, mul{factors}, x);
+ if (lost_factor.is_equal(_ex1)) {
+ // trivial lost factor
+ return factors;
+ }
+ if (!factors.empty() && factors[0].coeff.is_equal(1)) {
+ // multiply factor^1 with lost_factor
+ factors[0].rest *= lost_factor;
+ return factors;
+ }
+ // no factor^1: prepend lost_factor^1 to the results
+ epvector results = {expair(lost_factor, 1)};
+ std::move(factors.begin(), factors.end(), std::back_inserter(results));
return results;
}
// convert the argument from something in Q[X] to something in Z[X]
const numeric lcm = lcm_of_coefficients_denominators(a);
- const ex tmp = multiply_lcm(a,lcm);
+ const ex tmp = multiply_lcm(a, lcm);
// find the factors
epvector factors = sqrfree_yun(tmp, x);
+ if (factors.empty()) {
+ // the polynomial was a hidden zero
+ return _ex0;
+ }
// remove symbol x and proceed recursively with the remaining symbols
args.remove_first();
}
// Done with recursion, now construct the final result
- ex result = _ex1;
- for (auto & it : factors)
- result *= pow(it.rest, it.coeff);
-
- // Yun's algorithm does not account for constant factors. (For univariate
- // polynomials it works only in the monic case.) We can correct this by
- // inserting what has been lost back into the result. For completeness
- // we'll also have to recurse down that factor in the remaining variables.
- if (args.nops()>0)
- result *= sqrfree(quo(tmp, result, x), args);
- else
- result *= quo(tmp, result, x);
+ ex result = mul(factors);
// Put in the rational overall factor again and return
- return result * lcm.inverse();
+ return result * lcm.inverse();
}
// Find numerator and denominator
ex nd = numer_denom(a);
ex numer = nd.op(0), denom = nd.op(1);
-//clog << "numer = " << numer << ", denom = " << denom << endl;
+//std::clog << "numer = " << numer << ", denom = " << denom << std::endl;
// Convert N(x)/D(x) -> Q(x) + R(x)/D(x), so degree(R) < degree(D)
ex red_poly = quo(numer, denom, x), red_numer = rem(numer, denom, x).expand();
-//clog << "red_poly = " << red_poly << ", red_numer = " << red_numer << endl;
+//std::clog << "red_poly = " << red_poly << ", red_numer = " << red_numer << std::endl;
// Factorize denominator and compute cofactors
epvector yun = sqrfree_yun(denom, x);
- size_t yun_max_exponent = yun.empty() ? 0 : ex_to<numeric>(yun.back().coeff).to_int();
exvector factor, cofac;
+ size_t dim = 0;
for (size_t i=0; i<yun.size(); i++) {
numeric i_exponent = ex_to<numeric>(yun[i].coeff);
for (size_t j=0; j<i_exponent; j++) {
factor.push_back(pow(yun[i].rest, j+1));
+ dim += degree(yun[i].rest, x);
ex prod = _ex1;
for (size_t k=0; k<yun.size(); k++) {
if (yun[k].coeff == i_exponent)
cofac.push_back(prod.expand());
}
}
- size_t num_factors = factor.size();
-//clog << "factors : " << exprseq(factor) << endl;
-//clog << "cofactors: " << exprseq(cofac) << endl;
-
- // Construct coefficient matrix for decomposition
- int max_denom_deg = denom.degree(x);
- matrix sys(max_denom_deg + 1, num_factors);
- matrix rhs(max_denom_deg + 1, 1);
- for (int i=0; i<=max_denom_deg; i++) {
- for (size_t j=0; j<num_factors; j++)
- sys(i, j) = cofac[j].coeff(x, i);
- rhs(i, 0) = red_numer.coeff(x, i);
- }
-//clog << "coeffs: " << sys << endl;
-//clog << "rhs : " << rhs << endl;
-
- // Solve resulting linear system
- matrix vars(num_factors, 1);
- for (size_t i=0; i<num_factors; i++)
- vars(i, 0) = symbol();
+//std::clog << "factors : " << exprseq(factor) << std::endl;
+//std::clog << "cofactors: " << exprseq(cofac) << std::endl;
+
+ // Construct linear system for decomposition
+ matrix sys(dim, dim);
+ matrix rhs(dim, 1);
+ matrix vars(dim, 1);
+ for (size_t i=0, n=0, f=0; i<yun.size(); i++) {
+ size_t i_expo = to_int(ex_to<numeric>(yun[i].coeff));
+ for (size_t j=0; j<i_expo; j++) {
+ for (size_t k=0; k<size_t(degree(yun[i].rest, x)); k++) {
+ GINAC_ASSERT(n < dim && f < factor.size());
+
+ // column n of coefficient matrix
+ for (size_t r=0; r+k<dim; r++) {
+ sys(r+k, n) = cofac[f].coeff(x, r);
+ }
+
+ // element n of right hand side vector
+ rhs(n, 0) = red_numer.coeff(x, n);
+
+ // element n of free variables vector
+ vars(n, 0) = symbol();
+
+ n++;
+ }
+ f++;
+ }
+ }
+//std::clog << "coeffs: " << sys << std::endl;
+//std::clog << "rhs : " << rhs << std::endl;
+
+ // Solve resulting linear system and sum up decomposed fractions
matrix sol = sys.solve(vars, rhs);
+//std::clog << "sol : " << sol << std::endl;
+ ex sum = red_poly;
+ for (size_t i=0, n=0, f=0; i<yun.size(); i++) {
+ size_t i_expo = to_int(ex_to<numeric>(yun[i].coeff));
+ for (size_t j=0; j<i_expo; j++) {
+ ex frac_numer = 0;
+ for (size_t k=0; k<size_t(degree(yun[i].rest, x)); k++) {
+ GINAC_ASSERT(n < dim && f < factor.size());
+ frac_numer += sol(n, 0) * pow(x, k);
+ n++;
+ }
+ sum += frac_numer / factor[f];
- // Sum up decomposed fractions
- ex sum = 0;
- for (size_t i=0; i<num_factors; i++)
- sum += sol(i, 0) / factor[i];
+ f++;
+ }
+ }
- return red_poly + sum;
+ return sum;
}
/** Create a symbol for replacing the expression "e" (or return a previously
* assigned symbol). The symbol and expression are appended to repl, for
* a later application of subs().
+ * An entry in the replacement table repl can be changed in some cases.
+ * If it was altered, we need to provide the modifier for the previously build expressions.
+ * The modifier is an (ordered) list, because those substitutions need to be done in the
+ * incremental order.
+ * As an example let us consider a rationalisation of the expression
+ * e = exp(2*x)*cos(exp(2*x)+1)*exp(x)
+ * The first factor GiNaC denotes by something like symbol1 and will record:
+ * e =symbol1*cos(symbol1 + 1)*exp(x)
+ * repl = {symbol1 : exp(2*x)}
+ * Similarly, the second factor would be denoted as symbol2 and we will have
+ * e =symbol1*symbol2*exp(x)
+ * repl = {symbol1 : exp(2*x), symbol2 : cos(symbol1 + 1)}
+ * Denoting the third term as symbol3 GiNaC is willing to re-think exp(2*x) as
+ * symbol3^2 rather than just symbol1. Here are two issues:
+ * 1) The replacement "symbol1 -> symbol3^2" in the previous part of the expression
+ * needs to be done outside of the present routine;
+ * 2) The pair "symbol1 : exp(2*x)" shall be deleted from the replacement table repl.
+ * However, this will create illegal substitution "symbol2 : cos(symbol1 + 1)" with
+ * undefined symbol1.
+ * These both problems are mitigated through the additions of the record
+ * "symbol1==symbol3^2" to the list modifier. Changed length of the modifier signals
+ * to the calling code that the previous portion of the expression needs to be
+ * altered (it solves 1). Thus GiNaC can record now
+ * e =symbol3^2*symbol2*symbol3
+ * repl = {symbol2 : cos(symbol1 + 1), symbol3 : exp(x)}
+ * modifier = {symbol1==symbol3^2}
+ * Then, doing the backward substitutions the list modifier will be used to restore
+ * such iterative substitutions in the right way (this solves 2).
* @see ex::normal */
-static ex replace_with_symbol(const ex & e, exmap & repl, exmap & rev_lookup)
+static ex replace_with_symbol(const ex & e, exmap & repl, exmap & rev_lookup, lst & modifier)
{
// Since the repl contains replaced expressions we should search for them
ex e_replaced = e.subs(repl, subs_options::no_pattern);
if (it != rev_lookup.end())
return it->second;
+ // The expression can be the base of substituted power, which requires a more careful search
+ if (! is_a<numeric>(e_replaced))
+ for (auto & it : repl)
+ if (is_a<power>(it.second) && e_replaced.is_equal(it.second.op(0))) {
+ ex degree = pow(it.second.op(1), _ex_1);
+ if (is_a<numeric>(degree) && ex_to<numeric>(degree).is_integer())
+ return pow(it.first, degree);
+ }
+
+ // We treat powers and the exponent functions differently because
+ // they can be rationalised more efficiently
+ if (is_a<function>(e_replaced) && is_ex_the_function(e_replaced, exp)) {
+ for (auto & it : repl) {
+ if (is_a<function>(it.second) && is_ex_the_function(it.second, exp)) {
+ ex ratio = normal(e_replaced.op(0) / it.second.op(0));
+ if (is_a<numeric>(ratio) && ex_to<numeric>(ratio).is_rational()) {
+ // Different exponents can be treated as powers of the same basic equation
+ if (ex_to<numeric>(ratio).is_integer()) {
+ // If ratio is an integer then this is simply the power of the existing symbol.
+ // std::clog << e_replaced << " is a " << ratio << " power of " << it.first << std::endl;
+ return dynallocate<power>(it.first, ratio);
+ } else {
+ // otherwise we need to give the replacement pattern to change
+ // the previous expression...
+ ex es = dynallocate<symbol>();
+ ex Num = numer(ratio);
+ modifier.append(it.first == power(es, denom(ratio)));
+ // std::clog << e_replaced << " is power " << Num << " and "
+ // << it.first << " is power " << denom(ratio) << " of the common base "
+ // << exp(e_replaced.op(0)/Num) << std::endl;
+ // ... and modify the replacement tables
+ rev_lookup.erase(it.second);
+ rev_lookup.insert({exp(e_replaced.op(0)/Num), es});
+ repl.erase(it.first);
+ repl.insert({es, exp(e_replaced.op(0)/Num)});
+ return dynallocate<power>(es, Num);
+ }
+ }
+ }
+ }
+ } else if (is_a<power>(e_replaced) && !is_a<numeric>(e_replaced.op(0)) // We do not replace simple monomials like x^3 or sqrt(2)
+ && ! (is_a<symbol>(e_replaced.op(0))
+ && is_a<numeric>(e_replaced.op(1)) && ex_to<numeric>(e_replaced.op(1)).is_integer())) {
+ for (auto & it : repl) {
+ if (e_replaced.op(0).is_equal(it.second) // The base is an allocated symbol or base of power
+ || (is_a<power>(it.second) && e_replaced.op(0).is_equal(it.second.op(0)))) {
+ ex ratio; // We bind together two above cases
+ if (is_a<power>(it.second))
+ ratio = normal(e_replaced.op(1) / it.second.op(1));
+ else
+ ratio = e_replaced.op(1);
+ if (is_a<numeric>(ratio) && ex_to<numeric>(ratio).is_rational()) {
+ // Different powers can be treated as powers of the same basic equation
+ if (ex_to<numeric>(ratio).is_integer()) {
+ // If ratio is an integer then this is simply the power of the existing symbol.
+ //std::clog << e_replaced << " is a " << ratio << " power of " << it.first << std::endl;
+ return dynallocate<power>(it.first, ratio);
+ } else {
+ // otherwise we need to give the replacement pattern to change
+ // the previous expression...
+ ex es = dynallocate<symbol>();
+ ex Num = numer(ratio);
+ modifier.append(it.first == power(es, denom(ratio)));
+ //std::clog << e_replaced << " is power " << Num << " and "
+ // << it.first << " is power " << denom(ratio) << " of the common base "
+ // << pow(e_replaced.op(0), e_replaced.op(1)/Num) << std::endl;
+ // ... and modify the replacement tables
+ rev_lookup.erase(it.second);
+ rev_lookup.insert({pow(e_replaced.op(0), e_replaced.op(1)/Num), es});
+ repl.erase(it.first);
+ repl.insert({es, pow(e_replaced.op(0), e_replaced.op(1)/Num)});
+ return dynallocate<power>(es, Num);
+ }
+ }
+ }
+ }
+ // There is no existing substitution, thus we are creating a new one.
+ // This needs to be done separately to treat possible occurrences of
+ // b = e_replaced.op(0) elsewhere in the expression as pow(b, 1).
+ ex degree = pow(e_replaced.op(1), _ex_1);
+ if (is_a<numeric>(degree) && ex_to<numeric>(degree).is_integer()) {
+ ex es = dynallocate<symbol>();
+ modifier.append(e_replaced.op(0) == power(es, degree));
+ repl.insert({es, e_replaced});
+ rev_lookup.insert({e_replaced, es});
+ return es;
+ }
+ }
+
// Otherwise create new symbol and add to list, taking care that the
// replacement expression doesn't itself contain symbols from repl,
// because subs() is not recursive
/** Default implementation of ex::normal(). It normalizes the children and
* replaces the object with a temporary symbol.
* @see ex::normal */
-ex basic::normal(exmap & repl, exmap & rev_lookup) const
+ex basic::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
{
if (nops() == 0)
- return dynallocate<lst>({replace_with_symbol(*this, repl, rev_lookup), _ex1});
+ return dynallocate<lst>({replace_with_symbol(*this, repl, rev_lookup, modifier), _ex1});
normal_map_function map_normal;
- return dynallocate<lst>({replace_with_symbol(map(map_normal), repl, rev_lookup), _ex1});
+ size_t nmod = modifier.nops(); // To watch new modifiers to the replacement list
+ ex result = replace_with_symbol(map(map_normal), repl, rev_lookup, modifier);
+ for (size_t imod = nmod; imod < modifier.nops(); ++imod) {
+ exmap this_repl;
+ this_repl.insert(std::make_pair(modifier.op(imod).op(0), modifier.op(imod).op(1)));
+ result = result.subs(this_repl, subs_options::no_pattern);
+ }
+
+ // Sometimes we may obtain negative powers, they need to be placed to denominator
+ if (is_a<power>(result) && result.op(1).info(info_flags::negative))
+ return dynallocate<lst>({_ex1, power(result.op(0), -result.op(1))});
+ else
+ return dynallocate<lst>({result, _ex1});
}
/** Implementation of ex::normal() for symbols. This returns the unmodified symbol.
* @see ex::normal */
-ex symbol::normal(exmap & repl, exmap & rev_lookup) const
+ex symbol::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
{
return dynallocate<lst>({*this, _ex1});
}
* into re+I*im and replaces I and non-rational real numbers with a temporary
* symbol.
* @see ex::normal */
-ex numeric::normal(exmap & repl, exmap & rev_lookup) const
+ex numeric::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
{
numeric num = numer();
ex numex = num;
if (num.is_real()) {
if (!num.is_integer())
- numex = replace_with_symbol(numex, repl, rev_lookup);
+ numex = replace_with_symbol(numex, repl, rev_lookup, modifier);
} else { // complex
numeric re = num.real(), im = num.imag();
- ex re_ex = re.is_rational() ? re : replace_with_symbol(re, repl, rev_lookup);
- ex im_ex = im.is_rational() ? im : replace_with_symbol(im, repl, rev_lookup);
- numex = re_ex + im_ex * replace_with_symbol(I, repl, rev_lookup);
+ ex re_ex = re.is_rational() ? re : replace_with_symbol(re, repl, rev_lookup, modifier);
+ ex im_ex = im.is_rational() ? im : replace_with_symbol(im, repl, rev_lookup, modifier);
+ numex = re_ex + im_ex * replace_with_symbol(I, repl, rev_lookup, modifier);
}
// Denominator is always a real integer (see numeric::denom())
/** Implementation of ex::normal() for a sum. It expands terms and performs
* fractional addition.
* @see ex::normal */
-ex add::normal(exmap & repl, exmap & rev_lookup) const
+ex add::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
{
// Normalize children and split each one into numerator and denominator
exvector nums, dens;
nums.reserve(seq.size()+1);
dens.reserve(seq.size()+1);
+ size_t nmod = modifier.nops(); // To watch new modifiers to the replacement list
for (auto & it : seq) {
- ex n = ex_to<basic>(recombine_pair_to_ex(it)).normal(repl, rev_lookup);
+ ex n = ex_to<basic>(recombine_pair_to_ex(it)).normal(repl, rev_lookup, modifier);
nums.push_back(n.op(0));
dens.push_back(n.op(1));
}
- ex n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup);
+ ex n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup, modifier);
nums.push_back(n.op(0));
dens.push_back(n.op(1));
GINAC_ASSERT(nums.size() == dens.size());
auto num_it = nums.begin(), num_itend = nums.end();
auto den_it = dens.begin(), den_itend = dens.end();
//std::clog << " num = " << *num_it << ", den = " << *den_it << std::endl;
+ for (size_t imod = nmod; imod < modifier.nops(); ++imod) {
+ while (num_it != num_itend) {
+ *num_it = num_it->subs(modifier.op(imod), subs_options::no_pattern);
+ ++num_it;
+ *den_it = den_it->subs(modifier.op(imod), subs_options::no_pattern);
+ ++den_it;
+ }
+ // Reset iterators for the next round
+ num_it = nums.begin();
+ den_it = dens.begin();
+ }
+
ex num = *num_it++, den = *den_it++;
while (num_it != num_itend) {
//std::clog << " num = " << *num_it << ", den = " << *den_it << std::endl;
/** Implementation of ex::normal() for a product. It cancels common factors
* from fractions.
* @see ex::normal() */
-ex mul::normal(exmap & repl, exmap & rev_lookup) const
+ex mul::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
{
// Normalize children, separate into numerator and denominator
exvector num; num.reserve(seq.size());
exvector den; den.reserve(seq.size());
ex n;
+ size_t nmod = modifier.nops(); // To watch new modifiers to the replacement list
for (auto & it : seq) {
- n = ex_to<basic>(recombine_pair_to_ex(it)).normal(repl, rev_lookup);
+ n = ex_to<basic>(recombine_pair_to_ex(it)).normal(repl, rev_lookup, modifier);
num.push_back(n.op(0));
den.push_back(n.op(1));
}
- n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup);
+ n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup, modifier);
num.push_back(n.op(0));
den.push_back(n.op(1));
+ auto num_it = num.begin(), num_itend = num.end();
+ auto den_it = den.begin();
+ for (size_t imod = nmod; imod < modifier.nops(); ++imod) {
+ while (num_it != num_itend) {
+ *num_it = num_it->subs(modifier.op(imod), subs_options::no_pattern);
+ ++num_it;
+ *den_it = den_it->subs(modifier.op(imod), subs_options::no_pattern);
+ ++den_it;
+ }
+ num_it = num.begin();
+ den_it = den.begin();
+ }
// Perform fraction cancellation
return frac_cancel(dynallocate<mul>(num), dynallocate<mul>(den));
}
-/** Implementation of ex::normal([B) for powers. It normalizes the basis,
+/** Implementation of ex::normal() for powers. It normalizes the basis,
* distributes integer exponents to numerator and denominator, and replaces
* non-integer powers by temporary symbols.
* @see ex::normal */
-ex power::normal(exmap & repl, exmap & rev_lookup) const
+ex power::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
{
// Normalize basis and exponent (exponent gets reassembled)
- ex n_basis = ex_to<basic>(basis).normal(repl, rev_lookup);
- ex n_exponent = ex_to<basic>(exponent).normal(repl, rev_lookup);
+ size_t nmod = modifier.nops(); // To watch new modifiers to the replacement list
+ ex n_basis = ex_to<basic>(basis).normal(repl, rev_lookup, modifier);
+ for (size_t imod = nmod; imod < modifier.nops(); ++imod)
+ n_basis = n_basis.subs(modifier.op(imod), subs_options::no_pattern);
+
+ nmod = modifier.nops();
+ ex n_exponent = ex_to<basic>(exponent).normal(repl, rev_lookup, modifier);
+ for (size_t imod = nmod; imod < modifier.nops(); ++imod)
+ n_exponent = n_exponent.subs(modifier.op(imod), subs_options::no_pattern);
n_exponent = n_exponent.op(0) / n_exponent.op(1);
if (n_exponent.info(info_flags::integer)) {
if (n_exponent.info(info_flags::positive)) {
// (a/b)^x -> {sym((a/b)^x), 1}
- return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup), _ex1});
+ return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup, modifier), _ex1});
} else if (n_exponent.info(info_flags::negative)) {
if (n_basis.op(1).is_equal(_ex1)) {
// a^-x -> {1, sym(a^x)}
- return dynallocate<lst>({_ex1, replace_with_symbol(pow(n_basis.op(0), -n_exponent), repl, rev_lookup)});
+ return dynallocate<lst>({_ex1, replace_with_symbol(pow(n_basis.op(0), -n_exponent), repl, rev_lookup, modifier)});
} else {
// (a/b)^-x -> {sym((b/a)^x), 1}
- return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(1) / n_basis.op(0), -n_exponent), repl, rev_lookup), _ex1});
+ return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(1) / n_basis.op(0), -n_exponent), repl, rev_lookup, modifier), _ex1});
}
}
}
// (a/b)^x -> {sym((a/b)^x, 1}
- return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup), _ex1});
+ return dynallocate<lst>({replace_with_symbol(pow(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup, modifier), _ex1});
}
/** Implementation of ex::normal() for pseries. It normalizes each coefficient
* and replaces the series by a temporary symbol.
* @see ex::normal */
-ex pseries::normal(exmap & repl, exmap & rev_lookup) const
+ex pseries::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
{
epvector newseq;
for (auto & it : seq) {
newseq.push_back(expair(restexp, it.coeff));
}
ex n = pseries(relational(var,point), std::move(newseq));
- return dynallocate<lst>({replace_with_symbol(n, repl, rev_lookup), _ex1});
+ return dynallocate<lst>({replace_with_symbol(n, repl, rev_lookup, modifier), _ex1});
}
ex ex::normal() const
{
exmap repl, rev_lookup;
+ lst modifier;
- ex e = bp->normal(repl, rev_lookup);
+ ex e = bp->normal(repl, rev_lookup, modifier);
GINAC_ASSERT(is_a<lst>(e));
// Re-insert replaced symbols
- if (!repl.empty())
+ if (!repl.empty()) {
+ for(size_t i=0; i < modifier.nops(); ++i)
+ e = e.subs(modifier.op(i), subs_options::no_pattern);
e = e.subs(repl, subs_options::no_pattern);
+ }
// Convert {numerator, denominator} form back to fraction
return e.op(0) / e.op(1);
ex ex::numer() const
{
exmap repl, rev_lookup;
+ lst modifier;
- ex e = bp->normal(repl, rev_lookup);
+ ex e = bp->normal(repl, rev_lookup, modifier);
GINAC_ASSERT(is_a<lst>(e));
// Re-insert replaced symbols
if (repl.empty())
return e.op(0);
- else
+ else {
+ for(size_t i=0; i < modifier.nops(); ++i)
+ e = e.subs(modifier.op(i), subs_options::no_pattern);
+
return e.op(0).subs(repl, subs_options::no_pattern);
+ }
}
/** Get denominator of an expression. If the expression is not of the normal
ex ex::denom() const
{
exmap repl, rev_lookup;
+ lst modifier;
- ex e = bp->normal(repl, rev_lookup);
+ ex e = bp->normal(repl, rev_lookup, modifier);
GINAC_ASSERT(is_a<lst>(e));
// Re-insert replaced symbols
if (repl.empty())
return e.op(1);
- else
+ else {
+ for(size_t i=0; i < modifier.nops(); ++i)
+ e = e.subs(modifier.op(i), subs_options::no_pattern);
+
return e.op(1).subs(repl, subs_options::no_pattern);
+ }
}
/** Get numerator and denominator of an expression. If the expression is not
ex ex::numer_denom() const
{
exmap repl, rev_lookup;
+ lst modifier;
- ex e = bp->normal(repl, rev_lookup);
+ ex e = bp->normal(repl, rev_lookup, modifier);
GINAC_ASSERT(is_a<lst>(e));
// Re-insert replaced symbols
if (repl.empty())
return e;
- else
+ else {
+ for(size_t i=0; i < modifier.nops(); ++i)
+ e = e.subs(modifier.op(i), subs_options::no_pattern);
+
return e.subs(repl, subs_options::no_pattern);
+ }
}
ex power::to_polynomial(exmap & repl) const
{
if (exponent.info(info_flags::posint))
- return pow(basis.to_rational(repl), exponent);
+ return pow(basis.to_polynomial(repl), exponent);
else if (exponent.info(info_flags::negint))
{
ex basis_pref = collect_common_factors(basis);
x *= f;
}
- if (i == 0)
+ if (gc.is_zero())
gc = x;
else
gc = gcd(gc, x);
if (gc.is_equal(_ex1))
return e;
+ if (gc.is_zero())
+ return _ex0;
+
// The GCD is the factor we pull out
factor *= gc;
* computation, square-free factorization and rational function normalization. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* of special functions or implement the interface to the bignum package. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#include "numeric.h"
#include "ex.h"
#include "operators.h"
/**
* @brief Check if CLN integer can be converted into int
*
- * @sa http://www.ginac.de/pipermail/cln-list/2006-October/000248.html
+ * @sa https://www.ginac.de/pipermail/cln-list/2006-October/000248.html
*/
template<>
inline bool coerce<int, cln::cl_I>(int& dst, const cln::cl_I& arg)
/** The Binomial coefficients. It computes the binomial coefficients. For
* integer n and k and positive n this is the number of ways of choosing k
- * objects from n distinct objects. If n is negative, the formula
- * binomial(n,k) == (-1)^k*binomial(k-n-1,k) is used to compute the result. */
+ * objects from n distinct objects. If n is a negative integer, the formula
+ * binomial(n,k) == (-1)^k*binomial(k-n-1,k) (if k>=0)
+ * binomial(n,k) == (-1)^(n-k)*binomial(-k-1,n-k) (otherwise)
+ * is used to compute the result. */
const numeric binomial(const numeric &n, const numeric &k)
{
if (n.is_integer() && k.is_integer()) {
else
return *_num0_p;
} else {
- return _num_1_p->power(k)*binomial(k-n-(*_num1_p),k);
+ if (k.is_nonneg_integer())
+ return _num_1_p->power(k)*binomial(k-n-(*_num1_p), k);
+ else
+ return _num_1_p->power(n-k)*binomial(-k-(*_num1_p), n-k);
}
}
* Makes the interface to the underlying bignum package available. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
ex eval() const override;
ex evalf() const override;
ex subs(const exmap & m, unsigned options = 0) const override { return subs_one_level(m, options); } // overwrites basic::subs() for performance reasons
- ex normal(exmap & repl, exmap & rev_lookup) const override;
+ ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
ex to_rational(exmap & repl) const override;
ex to_polynomial(exmap & repl) const override;
numeric integer_content() const override;
* Implementation of GiNaC's overloaded operators. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's overloaded operators. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Debugging facilities for parser. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
**/
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's lexer. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This 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 lexer. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Code to deal with binary operators. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
}
}
+/// unary_expr: [+-] expression
+ex parser::parse_unary_expr()
+{
+ // Parse a binary expression with the priority of exponentiation
+ // or higher. Ignore the overall sign, because parse_primary()
+ // handles it for us.
+ get_next_tok(); // Skip [+-]
+ ex lhs = parse_primary();
+ ex e = parse_binop_rhs(get_tok_prec('^'), lhs);
+ return e;
+}
+
extern const numeric* _num_1_p;
static ex make_minus_expr(const exvector& args)
return dynallocate<mul>(args[0], rest);
}
+static ex make_power_expr(const exvector& args)
+{
+ size_t n = args.size();
+ ex p = pow(args[n - 2], args[n - 1]);
+ for (size_t i = n - 2; i > 0; i--) {
+ p = pow(args[i - 1], p);
+ }
+ return p;
+}
+
static ex make_binop_expr(const int binop, const exvector& args)
{
switch (binop) {
case '/':
return make_divide_expr(args);
case '^':
- if (args.size() != 2)
- throw std::invalid_argument(
- std::string(__func__)
- + ": power should have exactly 2 operands");
- return pow(args[0], args[1]);
+ return make_power_expr(args);
default:
throw std::invalid_argument(
std::string(__func__)
* Implementation of the parser context. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to parser context. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's parser. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "mul.h"
#include "constant.h"
#include "function.h"
+#include "operators.h"
#include <cstdint> // for uintptr_t
#include <sstream>
return list;
}
-extern const ex _ex0;
-
-/// unary_expr: [+-] expression
-ex parser::parse_unary_expr()
-{
- // Unlike most other parse_* method this one does NOT consume
- // current token so parse_binop_rhs() knows what kind of operator
- // is being parsed.
-
- // There are different kinds of expressions which need to be handled:
- // -a+b
- // -(a)
- // +a
- // +(a)
- // Delegate the work to parse_binop_rhs(), otherwise we end up
- // duplicating it here.
- ex lhs = _ex0; // silly trick
- ex e = parse_binop_rhs(0, lhs);
- return e;
-}
-
/// primary: identifier_expr | number_expr | paren_expr | unary_expr
ex parser::parse_primary()
{
case '{':
return parse_lst_expr();
case '-':
+ return -parse_unary_expr();
case '+':
return parse_unary_expr();
case lexer::token_type::literal:
* Interface to the parser. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Parser interface compatible with the old (bison/flex based) parser. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Chinese remainder algorithm. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GCD functions using Chinese remainder algorithm. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Utility functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to utility functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Garner's algorithm. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to Garner's algorithm. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Utility macros and functions for debugging. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of polynomial division in Z/Zp. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to polynomial division in Z/Zp. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Euclidean GCD and supporting functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Functions for finding an evaluation point. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Numerical evaluation of univariate polynomials. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* GCD using Euclidean algorithm. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Several GCD algorithms. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Heuristic GCD code. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Utility function for interpolation. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Chinese remainder algorithm. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of modular GCD. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to modular GCD. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Functions for Newton interpolation. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Functions to normalize polynomials in a field. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Functions to normalize polynomials in a field. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Functions to optimize the choice of variable for multivariate GCD. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* computations. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* GCD for polynomials in prime field. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GCD functions for polynomials over prime fields. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Chinese remainder algorithm. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Function to calculate the pseudo-remainder. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Factory for prime numbers. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Function to find primitive part of a multivariate polynomial. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Functions calculating remainders. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Functions calculating remainders. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Functions for polynomial ring arithmetic. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Utility functions for modular arithmetic. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* GCD function for univariate polynomials using PRS method. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to polynomials with integer and modular coefficients. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Input/Output function for univariate polynomials. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Output operators for polynomials. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's symbolic exponentiation (basis^exponent). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
static void print_sym_pow(const print_context & c, const symbol &x, int exp)
{
// Optimal output of integer powers of symbols to aid compiler CSE.
- // C.f. ISO/IEC 14882:2011, section 1.9 [intro execution], paragraph 15
+ // C.f. ISO/IEC 14882:2011, section 1.9 [intro.execution], paragraph 15
// to learn why such a parenthesation is really necessary.
if (exp == 1) {
x.print(c);
if (!are_ex_trivially_equal(basis, subsed_basis)
|| !are_ex_trivially_equal(exponent, subsed_exponent))
- return power(subsed_basis, subsed_exponent).subs_one_level(m, options);
+ return dynallocate<power>(subsed_basis, subsed_exponent);
if (!(options & subs_options::algebraic))
return subs_one_level(m, options);
ex coeff=(possign? _ex1 : _ex_1);
if (m.overall_coeff.info(info_flags::positive) && m.overall_coeff != _ex1)
prodseq.push_back(pow(m.overall_coeff, exponent));
- else if (m.overall_coeff.info(info_flags::negative) && m.overall_coeff != _ex_1)
+ else if (m.overall_coeff.info(info_flags::negative) && m.overall_coeff != _ex_1) {
prodseq.push_back(pow(-m.overall_coeff, exponent));
- else
+ coeff = -coeff;
+ } else
coeff *= m.overall_coeff;
// If positive/negative factors are found, then extract them.
* Interface to GiNaC's symbolic exponentiation (basis^exponent). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
ex series(const relational & s, int order, unsigned options = 0) const override;
ex subs(const exmap & m, unsigned options = 0) const override;
bool has(const ex & other, unsigned options = 0) const override;
- ex normal(exmap & repl, exmap & rev_lookup) const override;
+ ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
ex to_rational(exmap & repl) const override;
ex to_polynomial(exmap & repl) const override;
ex conjugate() const override;
* Implementation of helper classes for expression output. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Definition of helper classes for expression output. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* methods for series expansion. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* non-terminating series.
*
* @param rel_ expansion variable and point (must hold a relational)
- * @param ops_ vector of {coefficient, power} pairs (coefficient must not be zero)
- * @return newly constructed pseries */
+ * @param ops_ vector of {coefficient, power} pairs (coefficient must not be zero) */
pseries::pseries(const ex &rel_, const epvector &ops_)
: seq(ops_)
{
bool flag_redo = false;
try {
real_ldegree = buf.expand().ldegree(sym-r.rhs());
- } catch (std::runtime_error) {}
+ } catch (std::runtime_error &) {}
if (real_ldegree == 0) {
if ( factor < 0 ) {
// which can easily be solved given the starting value c_0 = (a_0)^p.
// For the more general case where the leading coefficient of A(x) is not
// a constant, just consider A2(x) = A(x)*x^m, with some integer m and
- // repeat the above derivation. The leading power of C2(x) = A2(x)^2 is
- // then of course x^(p*m) but the recurrence formula still holds.
+ // repeat the above derivation. The leading power of C2(x) = A2(x)^p is
+ // then of course a_0^p*x^(p*m) but the recurrence formula still holds.
if (seq.empty()) {
// as a special case, handle the empty (zero) series honoring the
else
return *this;
}
-
- const int ldeg = ldegree(var);
- if (!(p*ldeg).is_integer())
+
+ const int base_ldeg = ldegree(var);
+ if (!(p*base_ldeg).is_integer())
throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series");
+ int new_ldeg = (p*base_ldeg).to_int();
+
+ const int base_deg = degree(var);
+ int new_deg = deg;
+ if (p.is_pos_integer()) {
+ // No need to compute beyond p*base_deg.
+ new_deg = std::min((p*base_deg).to_int(), deg);
+ }
// adjust number of coefficients
- int numcoeff = deg - (p*ldeg).to_int();
+ int numcoeff = new_deg - new_ldeg;
+ if (new_deg < deg)
+ numcoeff += 1;
+
if (numcoeff <= 0) {
- epvector epv { expair(Order(_ex1), deg) };
- return dynallocate<pseries>(relational(var,point), std::move(epv));
+ return dynallocate<pseries>(relational(var, point),
+ epvector{{Order(_ex1), deg}});
}
// O(x^n)^(-m) is undefined
// Compute coefficients of the powered series
exvector co;
co.reserve(numcoeff);
- co.push_back(pow(coeff(var, ldeg), p));
+ co.push_back(pow(coeff(var, base_ldeg), p));
for (int i=1; i<numcoeff; ++i) {
ex sum = _ex0;
for (int j=1; j<=i; ++j) {
- ex c = coeff(var, j + ldeg);
+ ex c = coeff(var, j + base_ldeg);
if (is_order_function(c)) {
co.push_back(Order(_ex1));
break;
} else
sum += (p * j - (i - j)) * co[i - j] * c;
}
- co.push_back(sum / coeff(var, ldeg) / i);
+ co.push_back(sum / coeff(var, base_ldeg) / i);
}
// Construct new series (of non-zero coefficients)
epvector new_seq;
bool higher_order = false;
for (int i=0; i<numcoeff; ++i) {
- if (!co[i].is_zero())
- new_seq.emplace_back(expair(co[i], p * ldeg + i));
+ if (!co[i].is_zero()) {
+ new_seq.emplace_back(expair(co[i], new_ldeg + i));
+ }
if (is_order_function(co[i])) {
higher_order = true;
break;
}
}
- if (!higher_order)
- new_seq.emplace_back(expair(Order(_ex1), p * ldeg + numcoeff));
+ if (!higher_order && new_deg == deg) {
+ new_seq.emplace_back(expair{Order(_ex1), new_deg});
+ }
return pseries(relational(var,point), std::move(new_seq));
}
bool must_expand_basis = false;
try {
basis.subs(r, subs_options::no_pattern);
- } catch (pole_error) {
+ } catch (pole_error &) {
must_expand_basis = true;
}
bool exponent_is_regular = true;
try {
exponent.subs(r, subs_options::no_pattern);
- } catch (pole_error) {
+ } catch (pole_error &) {
exponent_is_regular = false;
}
if (!(real_ldegree*numexp).is_integer())
throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series");
- ex e = basis.series(r, (order + real_ldegree*(1-numexp)).to_int(), options);
+ int extra_terms = (real_ldegree*(1-numexp)).to_int();
+ ex e = basis.series(r, order + std::max(0, extra_terms), options);
ex result;
try {
result = ex_to<pseries>(e).power_const(numexp, order);
- } catch (pole_error) {
+ } catch (pole_error &) {
epvector ser { expair(Order(_ex1), order) };
result = pseries(r, std::move(ser));
}
* Interface to class for extended truncated power series. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
ex evalf() const override;
ex series(const relational & r, int order, unsigned options = 0) const override;
ex subs(const exmap & m, unsigned options = 0) const override;
- ex normal(exmap & repl, exmap & rev_lookup) const override;
+ ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
ex expand(unsigned options = 0) const override;
ex conjugate() const override;
ex real_part() const override;
* Reference-counted pointer template. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* GiNaC's class registrar (for class basic and all classes derived from it). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* GiNaC's class registrar (for class basic and all classes derived from it). */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of relations between expressions */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
return (o < oth.o) ? -1 : 1;
break;
}
- const int lcmpval = lh.compare(oth.rh);
- return (lcmpval!=0) ? lcmpval : rh.compare(oth.lh);
+ const int lcmpval = lh.compare(oth.lh);
+ return (lcmpval!=0) ? lcmpval : rh.compare(oth.rh);
}
bool relational::match_same_type(const basic & other) const
* unequal or undecidable). */
relational::operator relational::safe_bool() const
{
- const ex df = lh-rh;
- if (!is_exactly_a<numeric>(df))
- // cannot decide on non-numerical results
- return o==not_equal ? make_safe_bool(true) : make_safe_bool(false);
-
- switch (o) {
- case equal:
- return make_safe_bool(ex_to<numeric>(df).is_zero());
- case not_equal:
- return make_safe_bool(!ex_to<numeric>(df).is_zero());
- case less:
- return make_safe_bool(ex_to<numeric>(df)<(*_num0_p));
- case less_or_equal:
- return make_safe_bool(ex_to<numeric>(df)<=(*_num0_p));
- case greater:
- return make_safe_bool(ex_to<numeric>(df)>(*_num0_p));
- case greater_or_equal:
- return make_safe_bool(ex_to<numeric>(df)>=(*_num0_p));
- default:
- throw(std::logic_error("invalid relational operator"));
+ const ex df = lh-rh; // like ::canonical() method
+ // We treat numeric and symbolic expression differently
+ if (is_exactly_a<numeric>(df)) {
+ switch (o) {
+ case equal:
+ return make_safe_bool(ex_to<numeric>(df).is_zero());
+ case not_equal:
+ return make_safe_bool(!ex_to<numeric>(df).is_zero());
+ case less:
+ return make_safe_bool(ex_to<numeric>(df)<(*_num0_p));
+ case less_or_equal:
+ return make_safe_bool(ex_to<numeric>(df)<=(*_num0_p));
+ case greater:
+ return make_safe_bool(ex_to<numeric>(df)>(*_num0_p));
+ case greater_or_equal:
+ return make_safe_bool(ex_to<numeric>(df)>=(*_num0_p));
+ default:
+ throw(std::logic_error("invalid relational operator"));
+ }
+ } else {
+ // The conversion for symbolic expressions is based on the info flags
+ switch (o) {
+ case equal:
+ return make_safe_bool(df.is_zero());
+ case not_equal:
+ return make_safe_bool(! df.is_zero());
+ case less:
+ return make_safe_bool(df.info(info_flags::negative));
+ case less_or_equal:
+ return make_safe_bool((-df).info(info_flags::nonnegative));
+ case greater:
+ return make_safe_bool(df.info(info_flags::positive));
+ case greater_or_equal:
+ return make_safe_bool(df.info(info_flags::nonnegative));
+ default:
+ throw(std::logic_error("invalid relational operator"));
+ }
}
}
+/** Returns an equivalent relational with zero right-hand side.
+ */
+ex relational::canonical() const
+{
+ return relational(lh-rh, _ex0, o);
+}
+
} // namespace GiNaC
* Interface to relations between expressions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
void archive(archive_node& n) const override;
/** Read (a.k.a. deserialize) object from archive. */
void read_archive(const archive_node& n, lst& syms) override;
+ ex canonical() const;
+
protected:
ex eval_ncmul(const exvector & v) const override;
bool match_same_type(const basic & other) const override;
* in GiNaC functions */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* in GiNaC functions */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Wrapper template for making GiNaC classes out of C++ structures. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
ex series(const relational & r, int order, unsigned options = 0) const override { return inherited::series(r, order, options); }
// rational functions
- ex normal(exmap & repl, exmap & rev_lookup) const override { return inherited::normal(repl, rev_lookup); }
+ ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override { return inherited::normal(repl, rev_lookup, modifier); }
ex to_rational(exmap & repl) const override { return inherited::to_rational(repl); }
ex to_polynomial(exmap & repl) const override { return inherited::to_polynomial(repl); }
* Implementation of GiNaC's symbolic objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's symbolic objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
ex evalf() const override { return *this; } // overwrites basic::evalf() for performance reasons
ex series(const relational & s, int order, unsigned options = 0) const override;
ex subs(const exmap & m, unsigned options = 0) const override { return subs_one_level(m, options); } // overwrites basic::subs() for performance reasons
- ex normal(exmap & repl, exmap & rev_lookup) const override;
+ ex normal(exmap & repl, exmap & rev_lookup, lst & modifier) const override;
ex to_rational(exmap & repl) const override;
ex to_polynomial(exmap & repl) const override;
ex conjugate() const override;
* Implementation of GiNaC's symmetry definitions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's symmetry definitions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Implementation of GiNaC's special tensors. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's special tensors. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* but not of any interest to the user of the library. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
return factorial(n).div(d);
}
-//////////
-// flyweight chest of numbers is initialized here:
-//////////
/** How many static objects were created? Only the first one must create
* the static flyweights on the heap. */
int library_init::count = 0;
-// static numeric -120
-const numeric *_num_120_p;
-const ex _ex_120 = _ex_120;
-
-// static numeric -60
-const numeric *_num_60_p;
-const ex _ex_60 = _ex_60;
-
-// static numeric -48
-const numeric *_num_48_p;
-const ex _ex_48 = _ex_48;
-
-// static numeric -30
-const numeric *_num_30_p;
-const ex _ex_30 = _ex_30;
-
-// static numeric -25
-const numeric *_num_25_p;
-const ex _ex_25 = _ex_25;
-
-// static numeric -24
-const numeric *_num_24_p;
-const ex _ex_24 = _ex_24;
-
-// static numeric -20
-const numeric *_num_20_p;
-const ex _ex_20 = _ex_20;
-
-// static numeric -18
-const numeric *_num_18_p;
-const ex _ex_18 = _ex_18;
-
-// static numeric -15
-const numeric *_num_15_p;
-const ex _ex_15 = _ex_15;
-
-// static numeric -12
-const numeric *_num_12_p;
-const ex _ex_12 = _ex_12;
-
-// static numeric -11
-const numeric *_num_11_p;
-const ex _ex_11 = _ex_11;
-
-// static numeric -10
-const numeric *_num_10_p;
-const ex _ex_10 = _ex_10;
-
-// static numeric -9
-const numeric *_num_9_p;
-const ex _ex_9 = _ex_9;
-
-// static numeric -8
-const numeric *_num_8_p;
-const ex _ex_8 = _ex_8;
-
-// static numeric -7
-const numeric *_num_7_p;
-const ex _ex_7 = _ex_7;
-
-// static numeric -6
-const numeric *_num_6_p;
-const ex _ex_6 = _ex_6;
-
-// static numeric -5
-const numeric *_num_5_p;
-const ex _ex_5 = _ex_5;
-
-// static numeric -4
-const numeric *_num_4_p;
-const ex _ex_4 = _ex_4;
-
-// static numeric -3
-const numeric *_num_3_p;
-const ex _ex_3 = _ex_3;
-
-// static numeric -2
-const numeric *_num_2_p;
-const ex _ex_2 = _ex_2;
-
-// static numeric -1
-const numeric *_num_1_p;
-const ex _ex_1 = _ex_1;
-
-// static numeric -1/2
-const numeric *_num_1_2_p;
-const ex _ex_1_2= _ex_1_2;
-
-// static numeric -1/3
-const numeric *_num_1_3_p;
-const ex _ex_1_3= _ex_1_3;
-
-// static numeric -1/4
-const numeric *_num_1_4_p;
-const ex _ex_1_4= _ex_1_4;
-
-// static numeric 0
-const numeric *_num0_p;
-const basic *_num0_bp;
-const ex _ex0 = _ex0;
-
-// static numeric 1/4
-const numeric *_num1_4_p;
-const ex _ex1_4 = _ex1_4;
-
-// static numeric 1/3
-const numeric *_num1_3_p;
-const ex _ex1_3 = _ex1_3;
-
-// static numeric 1/2
-const numeric *_num1_2_p;
-const ex _ex1_2 = _ex1_2;
-
-// static numeric 1
-const numeric *_num1_p;
-const ex _ex1 = _ex1;
-
-// static numeric 2
-const numeric *_num2_p;
-const ex _ex2 = _ex2;
-
-// static numeric 3
-const numeric *_num3_p;
-const ex _ex3 = _ex3;
-
-// static numeric 4
-const numeric *_num4_p;
-const ex _ex4 = _ex4;
-
-// static numeric 5
-const numeric *_num5_p;
-const ex _ex5 = _ex5;
-
-// static numeric 6
-const numeric *_num6_p;
-const ex _ex6 = _ex6;
-
-// static numeric 7
-const numeric *_num7_p;
-const ex _ex7 = _ex7;
-
-// static numeric 8
-const numeric *_num8_p;
-const ex _ex8 = _ex8;
-
-// static numeric 9
-const numeric *_num9_p;
-const ex _ex9 = _ex9;
-
-// static numeric 10
-const numeric *_num10_p;
-const ex _ex10 = _ex10;
-
-// static numeric 11
-const numeric *_num11_p;
-const ex _ex11 = _ex11;
-
-// static numeric 12
-const numeric *_num12_p;
-const ex _ex12 = _ex12;
-
-// static numeric 15
-const numeric *_num15_p;
-const ex _ex15 = _ex15;
-
-// static numeric 18
-const numeric *_num18_p;
-const ex _ex18 = _ex18;
-
-// static numeric 20
-const numeric *_num20_p;
-const ex _ex20 = _ex20;
-
-// static numeric 24
-const numeric *_num24_p;
-const ex _ex24 = _ex24;
-
-// static numeric 25
-const numeric *_num25_p;
-const ex _ex25 = _ex25;
-
-// static numeric 30
-const numeric *_num30_p;
-const ex _ex30 = _ex30;
-
-// static numeric 48
-const numeric *_num48_p;
-const ex _ex48 = _ex48;
-
-// static numeric 60
-const numeric *_num60_p;
-const ex _ex60 = _ex60;
-
-// static numeric 120
-const numeric *_num120_p;
-const ex _ex120 = _ex120;
-
/** Ctor of static initialization helpers. The fist call to this is going
* to initialize the library, the others do nothing. */
library_init::library_init()
void library_init::init_unarchivers() { }
+
+//////////
+// Flyweight chest of numbers is re-initialized here. Note that this works
+// because the numeric* have been dynallocated by the library_init ctor before
+// (with the first module that has a static library_init object), so the
+// assignments here only increment their refcounts.
+//////////
+
+// static numeric -120
+const numeric *_num_120_p;
+const ex _ex_120 = ex(*_num_120_p);
+
+// static numeric -60
+const numeric *_num_60_p;
+const ex _ex_60 = ex(*_num_60_p);
+
+// static numeric -48
+const numeric *_num_48_p;
+const ex _ex_48 = ex(*_num_48_p);
+
+// static numeric -30
+const numeric *_num_30_p;
+const ex _ex_30 = ex(*_num_30_p);
+
+// static numeric -25
+const numeric *_num_25_p;
+const ex _ex_25 = ex(*_num_25_p);
+
+// static numeric -24
+const numeric *_num_24_p;
+const ex _ex_24 = ex(*_num_24_p);
+
+// static numeric -20
+const numeric *_num_20_p;
+const ex _ex_20 = ex(*_num_20_p);
+
+// static numeric -18
+const numeric *_num_18_p;
+const ex _ex_18 = ex(*_num_18_p);
+
+// static numeric -15
+const numeric *_num_15_p;
+const ex _ex_15 = ex(*_num_15_p);
+
+// static numeric -12
+const numeric *_num_12_p;
+const ex _ex_12 = ex(*_num_12_p);
+
+// static numeric -11
+const numeric *_num_11_p;
+const ex _ex_11 = ex(*_num_11_p);
+
+// static numeric -10
+const numeric *_num_10_p;
+const ex _ex_10 = ex(*_num_10_p);
+
+// static numeric -9
+const numeric *_num_9_p;
+const ex _ex_9 = ex(*_num_9_p);
+
+// static numeric -8
+const numeric *_num_8_p;
+const ex _ex_8 = ex(*_num_8_p);
+
+// static numeric -7
+const numeric *_num_7_p;
+const ex _ex_7 = ex(*_num_7_p);
+
+// static numeric -6
+const numeric *_num_6_p;
+const ex _ex_6 = ex(*_num_6_p);
+
+// static numeric -5
+const numeric *_num_5_p;
+const ex _ex_5 = ex(*_num_5_p);
+
+// static numeric -4
+const numeric *_num_4_p;
+const ex _ex_4 = ex(*_num_4_p);
+
+// static numeric -3
+const numeric *_num_3_p;
+const ex _ex_3 = ex(*_num_3_p);
+
+// static numeric -2
+const numeric *_num_2_p;
+const ex _ex_2 = ex(*_num_2_p);
+
+// static numeric -1
+const numeric *_num_1_p;
+const ex _ex_1 = ex(*_num_1_p);
+
+// static numeric -1/2
+const numeric *_num_1_2_p;
+const ex _ex_1_2= ex(*_num_1_2_p);
+
+// static numeric -1/3
+const numeric *_num_1_3_p;
+const ex _ex_1_3= ex(*_num_1_3_p);
+
+// static numeric -1/4
+const numeric *_num_1_4_p;
+const ex _ex_1_4= ex(*_num_1_4_p);
+
+// static numeric 0
+const numeric *_num0_p;
+const basic *_num0_bp;
+const ex _ex0 = ex(*_num0_p);
+
+// static numeric 1/4
+const numeric *_num1_4_p;
+const ex _ex1_4 = ex(*_num1_4_p);
+
+// static numeric 1/3
+const numeric *_num1_3_p;
+const ex _ex1_3 = ex(*_num1_3_p);
+
+// static numeric 1/2
+const numeric *_num1_2_p;
+const ex _ex1_2 = ex(*_num1_2_p);
+
+// static numeric 1
+const numeric *_num1_p;
+const ex _ex1 = ex(*_num1_p);
+
+// static numeric 2
+const numeric *_num2_p;
+const ex _ex2 = ex(*_num2_p);
+
+// static numeric 3
+const numeric *_num3_p;
+const ex _ex3 = ex(*_num3_p);
+
+// static numeric 4
+const numeric *_num4_p;
+const ex _ex4 = ex(*_num4_p);
+
+// static numeric 5
+const numeric *_num5_p;
+const ex _ex5 = ex(*_num5_p);
+
+// static numeric 6
+const numeric *_num6_p;
+const ex _ex6 = ex(*_num6_p);
+
+// static numeric 7
+const numeric *_num7_p;
+const ex _ex7 = ex(*_num7_p);
+
+// static numeric 8
+const numeric *_num8_p;
+const ex _ex8 = ex(*_num8_p);
+
+// static numeric 9
+const numeric *_num9_p;
+const ex _ex9 = ex(*_num9_p);
+
+// static numeric 10
+const numeric *_num10_p;
+const ex _ex10 = ex(*_num10_p);
+
+// static numeric 11
+const numeric *_num11_p;
+const ex _ex11 = ex(*_num11_p);
+
+// static numeric 12
+const numeric *_num12_p;
+const ex _ex12 = ex(*_num12_p);
+
+// static numeric 15
+const numeric *_num15_p;
+const ex _ex15 = ex(*_num15_p);
+
+// static numeric 18
+const numeric *_num18_p;
+const ex _ex18 = ex(*_num18_p);
+
+// static numeric 20
+const numeric *_num20_p;
+const ex _ex20 = ex(*_num20_p);
+
+// static numeric 24
+const numeric *_num24_p;
+const ex _ex24 = ex(*_num24_p);
+
+// static numeric 25
+const numeric *_num25_p;
+const ex _ex25 = ex(*_num25_p);
+
+// static numeric 30
+const numeric *_num30_p;
+const ex _ex30 = ex(*_num30_p);
+
+// static numeric 48
+const numeric *_num48_p;
+const ex _ex48 = ex(*_num48_p);
+
+// static numeric 60
+const numeric *_num60_p;
+const ex _ex60 = ex(*_num60_p);
+
+// static numeric 120
+const numeric *_num120_p;
+const ex _ex120 = ex(*_num120_p);
+
// comment skeleton for header files
* of any interest to the user of the library. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
// Generates all distinct permutations of a multiset.
// (Based on Aaron Williams' algorithm 1 from "Loopless Generation of
// Multiset Permutations using a Constant Number of Variables by Prefix
- // Shifts." <http://webhome.csc.uvic.ca/~haron/CoolMulti.pdf>)
+ // Shifts." <https://dl.acm.org/doi/pdf/10.5555/1496770.1496877>)
struct coolmulti {
// element of singly linked list
struct element {
--- /dev/null
+/** @file utils_multi_iterator.h
+ *
+ * Utilities for summing over multiple indices */
+
+/*
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GINAC_UTILS_MULTI_ITERATOR_H
+#define GINAC_UTILS_MULTI_ITERATOR_H
+
+#include <cstddef>
+#include <vector>
+#include <ostream>
+#include <iterator>
+
+namespace GiNaC {
+
+/**
+ *
+ * SFINAE test for distance
+ *
+ */
+template <typename T> class has_distance {
+private:
+ typedef char yes_type[1];
+ typedef char no_type[2];
+
+ template <typename C> static yes_type & test( decltype(std::distance<C>) ) ;
+ template <typename C> static no_type & test(...);
+
+public:
+ enum { value = sizeof(test<T>(0)) == sizeof(yes_type) };
+};
+
+/**
+ *
+ * For printing a multi-index:
+ * If the templates are used, where T is an iterator, printing the address where the iterator points to is not meaningful.
+ * However, we may print the difference to the starting point.
+ *
+ */
+template<typename T> typename std::enable_if<has_distance<T>::value, typename std::iterator_traits<T>::difference_type>::type format_index_value(const T & a, const T & b) {
+ return std::distance(a,b);
+}
+
+/**
+ *
+ * For all other cases we simply print the value.
+ *
+ */
+template<typename T> typename std::enable_if<!has_distance<T>::value, T>::type format_index_value(const T & a, const T & b) {
+ return b;
+}
+
+/**
+ *
+ * basic_multi_iterator is a base class.
+ *
+ * The base class itself does not do anything useful.
+ * A typical use of a class derived from basic_multi_iterator is
+ *
+ * multi_iterator_ordered<int> k(0,4,2);
+ *
+ * for( k.init(); !k.overflow(); k++) {
+ * std::cout << k << std::endl;
+ * }
+ *
+ * which prints out
+ *
+ * multi_iterator_ordered(0,1)
+ * multi_iterator_ordered(0,2)
+ * multi_iterator_ordered(0,3)
+ * multi_iterator_ordered(1,2)
+ * multi_iterator_ordered(1,3)
+ * multi_iterator_ordered(2,3)
+ *
+ * Individual components of k can be accessed with k[i] or k(i).
+ *
+ * All classes derived from basic_multi_iterator follow the same syntax.
+ *
+ */
+template<class T> class basic_multi_iterator {
+
+ // ctors
+public :
+ basic_multi_iterator(void);
+ explicit basic_multi_iterator(T B, T N, size_t k);
+ explicit basic_multi_iterator(T B, T N, const std::vector<T> & vv);
+
+ // dtor
+ virtual ~basic_multi_iterator();
+
+ // functions
+public :
+ size_t size(void) const;
+ bool overflow(void) const;
+ const std::vector<T> & get_vector(void) const;
+
+ // subscripting
+public :
+ T operator[](size_t i) const;
+ T & operator[](size_t i);
+
+ T operator()(size_t i) const;
+ T & operator()(size_t i);
+
+ // virtual functions
+public :
+ // initialization
+ virtual basic_multi_iterator<T> & init(void);
+ // postfix increment
+ virtual basic_multi_iterator<T> & operator++ (int);
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const basic_multi_iterator<TT> & v);
+
+ // member variables :
+protected :
+ T N;
+ T B;
+ std::vector<T> v;
+ bool flag_overflow;
+
+};
+
+/**
+ *
+ * The class multi_iterator_ordered defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ * B \le i_j < N
+ * \f]
+ * and
+ * \f[
+ * i_j < i_{j+1}.
+ * \f]
+ * It is assumed that \f$k>0\f$ and \f$ N-B \ge k \f$.
+ *
+ */
+template<class T> class multi_iterator_ordered : public basic_multi_iterator<T> {
+
+ // ctors
+public :
+ multi_iterator_ordered(void);
+ explicit multi_iterator_ordered(T B, T N, size_t k);
+ explicit multi_iterator_ordered(T B, T N, const std::vector<T> & vv);
+
+ // overriding virtual functions from base class
+public :
+ // initialization
+ basic_multi_iterator<T> & init(void);
+ // postfix increment
+ basic_multi_iterator<T> & operator++ (int);
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered<TT> & v);
+
+};
+
+/**
+ *
+ * The class multi_iterator_ordered_eq defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ * B \le i_j < N
+ * \f]
+ * and
+ * \f[
+ * i_j \le i_{j+1}.
+ * \f]
+ * It is assumed that \f$k>0\f$.
+ *
+ */
+template<class T> class multi_iterator_ordered_eq : public basic_multi_iterator<T> {
+
+ // ctors
+public :
+ multi_iterator_ordered_eq(void);
+ explicit multi_iterator_ordered_eq(T B, T N, size_t k);
+ explicit multi_iterator_ordered_eq(T B, T N, const std::vector<T> & vv);
+
+ // overriding virtual functions from base class
+public :
+ // initialization
+ basic_multi_iterator<T> & init(void);
+ // postfix increment
+ basic_multi_iterator<T> & operator++ (int);
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered_eq<TT> & v);
+
+};
+
+/**
+ *
+ * The class multi_iterator_ordered_eq_indv defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ * B \le i_j < N_j
+ * \f]
+ * and
+ * \f[
+ * i_j \le i_{j+1}.
+ * \f]
+ *
+ */
+template<class T> class multi_iterator_ordered_eq_indv : public basic_multi_iterator<T> {
+
+ // ctors
+public :
+ multi_iterator_ordered_eq_indv(void);
+ explicit multi_iterator_ordered_eq_indv(T B, const std::vector<T> & Nv, size_t k);
+ explicit multi_iterator_ordered_eq_indv(T B, const std::vector<T> & Nv, const std::vector<T> & vv);
+
+ // overriding virtual functions from base class
+public :
+ // initialization
+ basic_multi_iterator<T> & init(void);
+ // postfix increment
+ basic_multi_iterator<T> & operator++ (int);
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered_eq_indv<TT> & v);
+
+ // member variables :
+protected :
+ std::vector<T> Nv;
+};
+
+/**
+ *
+ * The class multi_iterator_counter defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ * B \le i_j < N
+ * \f]
+ *
+ */
+template<class T> class multi_iterator_counter : public basic_multi_iterator<T> {
+
+ // ctors
+public :
+ multi_iterator_counter(void);
+ explicit multi_iterator_counter(T B, T N, size_t k);
+ explicit multi_iterator_counter(T B, T N, const std::vector<T> & vv);
+
+ // overriding virtual functions from base class
+public :
+ // initialization
+ basic_multi_iterator<T> & init(void);
+ // postfix increment
+ basic_multi_iterator<T> & operator++ (int);
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_counter<TT> & v);
+
+};
+
+/**
+ *
+ * The class multi_iterator_counter_indv defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, such that
+ * \f[
+ * B \le i_j < N_j
+ * \f]
+ *
+ */
+template<class T> class multi_iterator_counter_indv : public basic_multi_iterator<T> {
+
+ // ctors
+public :
+ multi_iterator_counter_indv(void);
+ explicit multi_iterator_counter_indv(T B, const std::vector<T> & Nv, size_t k);
+ explicit multi_iterator_counter_indv(T B, const std::vector<T> & Nv, const std::vector<T> & vv);
+
+ // overriding virtual functions from base class
+public :
+ // initialization
+ basic_multi_iterator<T> & init(void);
+ // postfix increment
+ basic_multi_iterator<T> & operator++ (int);
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_counter_indv<TT> & v);
+
+ // member variables :
+protected :
+ std::vector<T> Nv;
+};
+
+/**
+ *
+ * The class multi_iterator_permutation defines a multi_iterator
+ * \f$(i_1,i_2,...,i_k)\f$, for which
+ * \f[
+ * B \le i_j < N
+ * \f]
+ * and
+ * \f[
+ * i_i \neq i_j
+ * \f]
+ * In particular, if \f$N-B=k\f$, multi_iterator_permutation loops over all
+ * permutations of \f$k\f$ elements.
+ *
+ */
+template<class T> class multi_iterator_permutation : public basic_multi_iterator<T> {
+
+ // ctors
+public :
+ multi_iterator_permutation(void);
+ explicit multi_iterator_permutation(T B, T N, size_t k);
+ explicit multi_iterator_permutation(T B, T N, const std::vector<T> & vv);
+
+ // overriding virtual functions from base class
+public :
+ // initialization
+ basic_multi_iterator<T> & init(void);
+ // postfix increment
+ basic_multi_iterator<T> & operator++ (int);
+
+ // new functions in this class
+ int get_sign(void) const;
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_permutation<TT> & v);
+
+};
+
+/**
+ *
+ * The class multi_iterator_shuffle defines a multi_iterator,
+ * which runs over all shuffles of a and b.
+ *
+ */
+template<class T> class multi_iterator_shuffle : public basic_multi_iterator<T> {
+
+ // ctors
+public :
+ multi_iterator_shuffle(void);
+ explicit multi_iterator_shuffle(const std::vector<T> & a, const std::vector<T> & b);
+
+ // overriding virtual functions from base class
+public :
+ // initialization
+ basic_multi_iterator<T> & init(void);
+ // postfix increment
+ basic_multi_iterator<T> & operator++ (int);
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_shuffle<TT> & v);
+
+ // member variables :
+protected :
+ size_t N_internal;
+ std::vector<size_t> v_internal;
+ std::vector<T> v_orig;
+};
+
+/**
+ *
+ * The class multi_iterator_shuffle_prime defines a multi_iterator,
+ * which runs over all shuffles of a and b, excluding the first one (a,b).
+ *
+ */
+template<class T> class multi_iterator_shuffle_prime : public multi_iterator_shuffle<T> {
+
+ // ctors
+public :
+ multi_iterator_shuffle_prime(void);
+ explicit multi_iterator_shuffle_prime(const std::vector<T> & a, const std::vector<T> & b);
+
+ // overriding virtual functions from base class
+public :
+ // initialization
+ basic_multi_iterator<T> & init(void);
+
+ // I/O operators
+ template <class TT> friend std::ostream & operator<< (std::ostream & os, const multi_iterator_shuffle_prime<TT> & v);
+};
+
+// ----------------------------------------------------------------------------------------------------------------
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline basic_multi_iterator<T>::basic_multi_iterator(void) : N(), B(), v(), flag_overflow(false)
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N, lower limit B and size k .
+ *
+ */
+template<class T> inline basic_multi_iterator<T>::basic_multi_iterator(T BB, T NN, size_t k) : N(NN), B(BB), v(k), flag_overflow(false)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline basic_multi_iterator<T>::basic_multi_iterator(T BB, T NN, const std::vector<T> & vv) : N(NN), B(BB), v(vv), flag_overflow(false)
+{}
+
+/**
+ *
+ * Destructor
+ *
+ */
+template<class T> inline basic_multi_iterator<T>::~basic_multi_iterator()
+{}
+
+// functions
+
+/**
+ *
+ * Returns the size of a multi_iterator.
+ *
+ */
+template<class T> inline size_t basic_multi_iterator<T>::size(void) const
+{
+ return v.size();
+}
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ * (n_1,n_2,n_3,...,n_k) = (B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & basic_multi_iterator<T>::init(void)
+{
+ flag_overflow = false;
+
+ for ( size_t i=0; i<v.size(); i++) {
+ v[i] = B;
+ }
+ return *this;
+}
+
+/**
+ *
+ * Return the overflow flag.
+ *
+ */
+template<class T> inline bool basic_multi_iterator<T>::overflow(void) const
+{
+ return flag_overflow;
+}
+
+/**
+ *
+ * Returns a reference to the vector v.
+ *
+ */
+template<class T> inline const std::vector<T> & basic_multi_iterator<T>::get_vector(void) const
+{
+ return v;
+}
+
+// subscripting
+
+/**
+ *
+ * Subscription via []
+ *
+ */
+template<class T> inline T basic_multi_iterator<T>::operator[](size_t i) const
+{
+ return v[i];
+}
+
+/**
+ *
+ * Subscription via []
+ *
+ */
+template<class T> inline T & basic_multi_iterator<T>::operator[](size_t i)
+{
+ return v[i];
+}
+
+/**
+ *
+ * Subscription via ()
+ *
+ */
+template<class T> inline T basic_multi_iterator<T>::operator()(size_t i) const
+{
+ return v[i];
+}
+
+/**
+ *
+ * Subscription via ()
+ *
+ */
+template<class T> inline T & basic_multi_iterator<T>::operator()(size_t i)
+{
+ return v[i];
+}
+
+
+/**
+ *
+ * No effect for basic_multi_iterator
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & basic_multi_iterator<T>::operator++ (int)
+{
+ return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator prints out as
+ * basic_multi_iterator(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const basic_multi_iterator<T> & v)
+{
+ os << "basic_multi_iterator(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_ordered<T>::multi_iterator_ordered(void) : basic_multi_iterator<T>()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_ordered<T>::multi_iterator_ordered(T B, T N, size_t k) : basic_multi_iterator<T>(B,N,k)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_ordered<T>::multi_iterator_ordered(T B, T N, const std::vector<T> & v) : basic_multi_iterator<T>(B,N,v)
+{}
+
+// functions
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ * (n_1,n_2,n_3,...,n_k) = (B+0,B+1,B+2,...,B+k-1)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered<T>::init(void)
+{
+ this->flag_overflow = false;
+ T it = this->B;
+
+ for ( size_t i=0; i < this->v.size(); i++) {
+ this->v[i] = it;
+ it++;
+ }
+ return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered<T>::operator++ (int)
+{
+ int k = this->size();
+ int j = k - 1;
+ T Upper_limit = this->N;
+
+ while ( j>0 ) {
+ this->v[j]++;
+ if ( this->v[j] == Upper_limit ) {
+ j--;
+ Upper_limit--;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (j==0) {
+ this->v[j]++;
+ if (this->v[j] == Upper_limit) this->flag_overflow=true;
+ }
+
+ if ( j>= 0) {
+ for (int jj=j+1;jj<k;jj++) {
+ this->v[jj] = this->v[jj-1];
+ this->v[jj]++;
+ }
+ }
+
+ return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_ordered prints out as
+ * multi_iterator_ordered(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered<T> & v)
+{
+ os << "multi_iterator_ordered(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq<T>::multi_iterator_ordered_eq(void) : basic_multi_iterator<T>()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq<T>::multi_iterator_ordered_eq(T B, T N, size_t k) : basic_multi_iterator<T>(B,N,k)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq<T>::multi_iterator_ordered_eq(T B, T N, const std::vector<T> & v) : basic_multi_iterator<T>(B,N,v)
+{}
+
+// functions
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ * (n_1,n_2,...,n_k) = (B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered_eq<T>::init(void)
+{
+ this->flag_overflow = false;
+
+ for ( size_t i=0; i < this->v.size(); i++) {
+ this->v[i] = this->B;
+ }
+ return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered_eq<T>::operator++ (int)
+{
+ int k = this->size();
+ int j = k - 1;
+
+ while ( j>0 ) {
+ this->v[j]++;
+ if ( this->v[j] == this->N ) {
+ j--;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (j==0) {
+ this->v[j]++;
+ if (this->v[j] == this->N) {
+ this->flag_overflow=true;
+ }
+ }
+
+ if ( j>= 0) {
+ for (int jj=j+1;jj<k;jj++) {
+ this->v[jj] = this->v[jj-1];
+ }
+ }
+
+ return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_ordered_eq prints out as
+ * multi_iterator_ordered_eq(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered_eq<T> & v)
+{
+ os << "multi_iterator_ordered_eq(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq_indv<T>::multi_iterator_ordered_eq_indv(void) : basic_multi_iterator<T>(), Nv()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq_indv<T>::multi_iterator_ordered_eq_indv(T B, const std::vector<T> & Nvv, size_t k) : basic_multi_iterator<T>(B,B,k), Nv(Nvv)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_ordered_eq_indv<T>::multi_iterator_ordered_eq_indv(T B, const std::vector<T> & Nvv, const std::vector<T> & v) : basic_multi_iterator<T>(B,B,v), Nv(Nvv)
+{}
+
+// functions
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ * (n_1,n_2,n_3,...,n_k) = (B,B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered_eq_indv<T>::init(void)
+{
+ this->flag_overflow = false;
+
+ for ( size_t i=0; i < this->v.size(); i++) {
+ this->v[i] = this->B;
+ }
+ return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_ordered_eq_indv<T>::operator++ (int)
+{
+ int k = this->size();
+ int j = k - 1;
+
+ while ( j>0 ) {
+ this->v[j]++;
+ if ( this->v[j] == Nv[j] ) {
+ j--;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (j==0) {
+ this->v[j]++;
+ if (this->v[j] == Nv[j]) {
+ this->flag_overflow=true;
+ }
+ }
+
+ if ( j>= 0) {
+ for (int jj=j+1;jj<k;jj++) {
+ this->v[jj] = this->v[jj-1];
+ }
+ }
+
+ return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_ordered_eq_indv prints out as
+ * multi_iterator_ordered_eq_indv(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_ordered_eq_indv<T> & v)
+{
+ os << "multi_iterator_ordered_eq_indv(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_counter<T>::multi_iterator_counter(void) : basic_multi_iterator<T>()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_counter<T>::multi_iterator_counter(T B, T N, size_t k) : basic_multi_iterator<T>(B,N,k)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_counter<T>::multi_iterator_counter(T B, T N, const std::vector<T> & v) : basic_multi_iterator<T>(B,N,v)
+{}
+
+// functions
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ * (n_1,n_2,n_3,...,n_k) = (B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_counter<T>::init(void)
+{
+ this->flag_overflow = false;
+
+ for ( size_t i=0; i < this->v.size(); i++) {
+ this->v[i] = this->B;
+ }
+ return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_counter<T>::operator++ (int)
+{
+ int k = this->size();
+ int j = k - 1;
+
+ while ( j>0 ) {
+ this->v[j]++;
+ if ( this->v[j] == this->N ) {
+ this->v[j] = this->B;
+ j--;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (j==0) {
+ this->v[j]++;
+ if (this->v[j] == this->N) {
+ this->v[j] = this->B;
+ this->flag_overflow=true;
+ }
+ }
+
+ return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_counter prints out as
+ * multi_iterator_counter(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_counter<T> & v)
+{
+ os << "multi_iterator_counter(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_counter_indv<T>::multi_iterator_counter_indv(void) : basic_multi_iterator<T>(), Nv()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_counter_indv<T>::multi_iterator_counter_indv(T B, const std::vector<T> & Nvv, size_t k) : basic_multi_iterator<T>(B,B,k), Nv(Nvv)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_counter_indv<T>::multi_iterator_counter_indv(T B, const std::vector<T> & Nvv, const std::vector<T> & v) : basic_multi_iterator<T>(B,B,v), Nv(Nvv)
+{}
+
+// functions
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ * (n_1,n_2,n_3,...,n_k) = (B,B,...,B)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_counter_indv<T>::init(void)
+{
+ this->flag_overflow = false;
+
+ for ( size_t i=0; i < this->v.size(); i++) {
+ this->v[i] = this->B;
+ }
+ return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_counter_indv<T>::operator++ (int)
+{
+ int k = this->size();
+ int j = k - 1;
+
+ while ( j>0 ) {
+ this->v[j]++;
+ if ( this->v[j] == Nv[j] ) {
+ this->v[j] = this->B;
+ j--;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (j==0) {
+ this->v[j]++;
+ if (this->v[j] == Nv[j]) {
+ this->v[j] = this->B;
+ this->flag_overflow=true;
+ }
+ }
+
+ return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_counter_indv prints out as
+ * multi_iterator_counter_indv(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_counter_indv<T> & v)
+{
+ os << "multi_iterator_counter_indv(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_permutation<T>::multi_iterator_permutation(void) : basic_multi_iterator<T>()
+{}
+
+/**
+ *
+ * Construct a multi_iterator with upper limit N and size k .
+ *
+ */
+template<class T> inline multi_iterator_permutation<T>::multi_iterator_permutation(T B, T N, size_t k) : basic_multi_iterator<T>(B,N,k)
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_permutation<T>::multi_iterator_permutation(T B, T N, const std::vector<T> & v) : basic_multi_iterator<T>(B,N,v)
+{}
+
+// functions
+
+/**
+ *
+ * Initialize the multi-index to
+ * \f[
+ * (n_1,n_2,n_3,...,n_k) = (B+0,B+1,B+2,...,B+k-1)
+ * \f]
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_permutation<T>::init(void)
+{
+ this->flag_overflow = false;
+ T it = this->B;
+
+ for ( size_t i=0; i < this->v.size(); i++) {
+ this->v[i] = it;
+ it++;
+ }
+ return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_permutation<T>::operator++ (int)
+{
+ int k = this->size();
+ int j = k - 1;
+
+ while ( j>=0 ) {
+ bool flag_have_already = true;
+ while ( flag_have_already ) {
+ this->v[j]++;
+
+ // update flag_have_already
+ flag_have_already = false;
+ for (int ii=0; ii<j; ii++) {
+ if (this->v[j] == this->v[ii]) {
+ flag_have_already = true;
+ }
+ }
+ }
+
+ if ( this->v[j] == this->N ) {
+ j--;
+ }
+ else {
+ break;
+ }
+ }
+
+ for (int l=j+1; l<k; l++) {
+ this->v[l] = this->B;
+
+ bool flag_have_already;
+ do {
+ flag_have_already = false;
+ for (int ii=0; ii<l; ii++) {
+ if (this->v[l] == this->v[ii]) {
+ flag_have_already = true;
+ }
+ }
+ if (flag_have_already) {
+ this->v[l]++;
+ }
+ }
+ while (flag_have_already);
+ }
+
+ // check for overflow
+ this->flag_overflow = true;
+ T it = this->B;
+ for (int ii=0; ii<k; ii++) {
+ if (this->v[ii] != it) {
+ this->flag_overflow = false;
+ }
+ it++;
+ }
+
+ return *this;
+}
+
+/**
+ *
+ * Returns the sign of the permutation, defined by
+ * \f[
+ * \left(-1\right)^{n_{inv}},
+ * \f]
+ * where \f$ n_{inv} \f$ is the number of inversions, e.g. the
+ * number of pairs \f$ i < j \f$ for which
+ * \f[
+ * n_i > n_j.
+ * \f]
+ *
+ */
+template<class T> inline int multi_iterator_permutation<T>::get_sign() const
+{
+ int sign = 1;
+ int k = this->size();
+
+ for ( int i=0; i<k; i++) {
+ for ( int j=i+1; j<k; j++) {
+ // works only for random-access iterators
+ if ( this->v[i] > this->v[j] ) {
+ sign = -sign;
+ }
+ }
+ }
+
+ return sign;
+}
+
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_permutation prints out as
+ * multi_iterator_permutation(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_permutation<T> & v)
+{
+ os << "multi_iterator_permutation(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_shuffle<T>::multi_iterator_shuffle(void) : basic_multi_iterator<T>(), N_internal(), v_internal(), v_orig()
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_shuffle<T>::multi_iterator_shuffle(const std::vector<T> & a, const std::vector<T> & b) : basic_multi_iterator<T>(), N_internal(), v_internal(), v_orig()
+{
+ this->B = a[0];
+
+ for (size_t i=0; i<a.size(); i++) {
+ this->v.push_back( a[i] );
+ this->v_orig.push_back( a[i] );
+ this->v_internal.push_back( i );
+ }
+ for (size_t i=0; i<b.size(); i++) {
+ this->v.push_back( b[i] );
+ this->v_orig.push_back( b[i] );
+ }
+ this->N_internal = this->v.size();
+}
+
+// functions
+
+/**
+ *
+ * Initialize the multi-index to the first shuffle.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_shuffle<T>::init(void)
+{
+ this->flag_overflow = false;
+
+ for ( size_t i=0; i < this->v_internal.size(); i++) {
+ this->v_internal[i] = i;
+ }
+ for ( size_t i=0; i < this->v.size(); i++) {
+ this->v[i] = this->v_orig[i];
+ }
+ return *this;
+}
+
+/**
+ *
+ * The postfix increment operator allows to
+ * write for a multi-index n++, which will
+ * update n to the next configuration.
+ *
+ * If n is in the last configuration and the
+ * increment operator ++ is applied to n,
+ * the overflow flag will be raised.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_shuffle<T>::operator++ (int)
+{
+ int k = this->v_internal.size();
+ int j = k - 1;
+ size_t Upper_limit = this->N_internal;
+
+ while ( j>0 ) {
+ this->v_internal[j]++;
+ if ( this->v_internal[j] == Upper_limit ) {
+ j--;
+ Upper_limit--;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (j==0) {
+ this->v_internal[j]++;
+ if (this->v_internal[j] == Upper_limit) {
+ this->flag_overflow=true;
+ }
+ }
+
+ if ( j>= 0) {
+ for (int jj=j+1;jj<k;jj++) {
+ this->v_internal[jj] = this->v_internal[jj-1];
+ this->v_internal[jj]++;
+ }
+ }
+
+ // update v
+ if ( !(this->flag_overflow) ) {
+ size_t i_a = 0;
+ size_t i_b = 0;
+ size_t i_all = 0;
+ for (size_t j=0; j<k; j++) {
+ for (size_t i=i_all; i < this->v_internal[j]; i++) {
+ this->v[i_all] = this->v_orig[k+i_b];
+ i_b++;
+ i_all++;
+ }
+ this->v[i_all] = this->v_orig[i_a];
+ i_a++;
+ i_all++;
+ }
+ for (size_t i = this->v_internal[k-1]+1; i < this->v.size(); i++) {
+ this->v[i_all] = this->v_orig[k+i_b];
+ i_b++;
+ i_all++;
+ }
+ }
+
+ return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_shuffle prints out as
+ * multi_iterator_shuffle(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_shuffle<T> & v)
+{
+ os << "multi_iterator_shuffle(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+
+
+// ctors
+
+/**
+ *
+ * Default constructor
+ *
+ */
+template<class T> inline multi_iterator_shuffle_prime<T>::multi_iterator_shuffle_prime(void) : multi_iterator_shuffle<T>()
+{}
+
+/**
+ *
+ * Construct from a vector.
+ *
+ */
+template<class T> inline multi_iterator_shuffle_prime<T>::multi_iterator_shuffle_prime(const std::vector<T> & a, const std::vector<T> & b) : multi_iterator_shuffle<T>(a,b)
+{}
+
+// functions
+
+/**
+ *
+ * Initialize the multi-index to the first shuffle.
+ *
+ */
+template<class T> inline basic_multi_iterator<T> & multi_iterator_shuffle_prime<T>::init(void)
+{
+ this->flag_overflow = false;
+
+ for ( size_t i=0; i < this->v_internal.size(); i++) {
+ this->v_internal[i] = i;
+ }
+ for ( size_t i=0; i < this->v.size(); i++) {
+ this->v[i] = this->v_orig[i];
+ }
+
+ (*this)++;
+
+ return *this;
+}
+
+// I/O operators
+
+/**
+ *
+ * Output operator. A multi_iterator_shuffle_prime prints out as
+ * multi_iterator_shuffle_prime(\f$n_0,n_1,...\f$).
+ *
+ */
+template<class T> inline std::ostream & operator<< (std::ostream & os, const multi_iterator_shuffle_prime<T> & v)
+{
+ os << "multi_iterator_shuffle_prime(";
+ for ( size_t i=0; i<v.size(); i++) {
+ if (i>0) {
+ os << ",";
+ }
+ os << format_index_value(v.B,v(i));
+ }
+
+ return os << ")";
+}
+
+} // namespace GiNaC
+
+#endif // ndef GINAC_UTILS_MULTI_ITERATOR_H
* GiNaC library version information. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#define GINACLIB_MAJOR_VERSION 1
/* Minor version of GiNaC */
-#define GINACLIB_MINOR_VERSION 7
+#define GINACLIB_MINOR_VERSION 8
/* Micro version of GiNaC */
-#define GINACLIB_MICRO_VERSION 8
+#define GINACLIB_MICRO_VERSION 7
// GiNaC library version information. It has very little to do with GiNaC
// version number. In particular, library version is OS dependent.
// increasing. This doesn't matter, though: there is not incurred cost
// for numbers that are omitted, except for shrinking the available space
// of leftover numbers. Not something we need to worry about yet. ;-)
-// TODO, when setting GINAC_LT_REVISION to 0:
+//
+// On Linux, the SONAME is libginac.so.$(GINAC_LT_CURRENT)-$(GINAC_LT_AGE).
+//
+// TODO, when breaking the SONAME:
// * change matrix inverse to use default argument (twice)
-// * remove interfaces marked as deprecated
-#define GINAC_LT_CURRENT 10
-#define GINAC_LT_REVISION 2
-#define GINAC_LT_AGE 4
+// * check for interfaces marked as deprecated
+#define GINAC_LT_CURRENT 12
+#define GINAC_LT_REVISION 6
+#define GINAC_LT_AGE 1
/*
* GiNaC archive file version information.
* Implementation of GiNaC's wildcard objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Interface to GiNaC's wildcard objects. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- /dev/null
+ginsh
+ginsh.1
+ginsh_parser.cpp
+ginsh_parser.hpp
+ginsh_lexer.cpp
+ginsh_op_help.h
+ginsh_fcn_help.h
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/../ginac
- ${CMAKE_CURRENT_BINARY_DIR}/../ginac
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_BINARY_DIR})
-add_definitions(-DIN_GINAC)
bison_target(ginsh_parser
ginsh_parser.ypp
ginsh_fcn_help.py
ginsh_op_help.py
)
+set(ginsh_include_directories ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
if (READLINE_FOUND)
- include_directories(${READLINE_INCLUDE_DIRS})
+ set(ginsh_include_directories ${ginsh_include_directories} ${READLINE_INCLUDE_DIRS})
endif()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ginsh_fcn_help.h
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_fcn_help.py -o ginsh_fcn_help.h ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in
+ COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_fcn_help.py -o ginsh_fcn_help.h ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_fcn_help.py
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ginsh_op_help.h
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_op_help.py -o ginsh_op_help.h ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in
+ COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_op_help.py -o ginsh_op_help.h ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ginsh.1.in ${CMAKE_CURRENT_SOURCE_DIR}/ginsh_op_help.py
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
add_executable(ginsh ${ginsh_SOURCES} ${ginsh_HEADERS})
-target_link_libraries(ginsh ginac ${ginsh_extra_libs} ${LIBDL_LIBRARIES})
-install(TARGETS ginsh RUNTIME DESTINATION "${BIN_INSTALL_DIR}")
+target_link_libraries(ginsh ginac::ginac ${ginsh_extra_libs})
+target_include_directories(ginsh PRIVATE ${ginsh_include_directories})
+target_compile_definitions(ginsh PRIVATE HAVE_CONFIG_H)
+install(TARGETS ginsh RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
.BI series( expression ", " relation-or-symbol ", " order )
\- series expansion
.br
+.BI series_to_poly( series )
+\- convert a series into a polynomial by dropping the Order() term
+.br
.BI sprem( expression ", " expression ", " symbol )
\- sparse pseudo-remainder of polynomials
.br
.BI sqrfree( "expression [" ", " symbol-list] )
\- square-free factorization of a polynomial
.br
+.BI sqrfree_parfrac( expression ", " symbol )
+\- square-free partial fraction decomposition of rational function
+.br
.BI sqrt( expression )
\- square root
.br
number 0, the second argument number 1, etc.
.SH AUTHOR
.TP
-The GiNaC Group:
-.br
-Christian Bauer <Christian.Bauer@uni-mainz.de>
-.br
-Alexander Frink <Alexander.Frink@uni-mainz.de>
-.br
-Richard Kreckel <Richard.Kreckel@uni-mainz.de>
-.br
-Jens Vollinga <vollinga@thep.physik.uni-mainz.de>
+The GiNaC maintainers <https://www.ginac.de/>.
.SH SEE ALSO
GiNaC Tutorial \- An open framework for symbolic computation within the
C++ programming language
.PP
CLN \- A Class Library for Numbers, Bruno Haible
.SH COPYRIGHT
-Copyright \(co 1999-2019 Johannes Gutenberg Universit\(:at Mainz, Germany
+Copyright \(co 1999-2023 Johannes Gutenberg Universit\(:at Mainz, Germany
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*
* Global definitions for ginsh.
*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <iostream>
#include <string>
-using namespace std;
-
#ifdef HAVE_READLINE_READLINE_H
extern "C" {
#include <readline/readline.h>
#include <ginac/ginac.h>
#endif
-using namespace GiNaC;
-
// yacc stack type
-#define YYSTYPE ex
+#define YYSTYPE GiNaC::ex
// lex functions/variables
extern int yyerror(const char *s);
extern char **file_list;
// Table of all used symbols
-typedef map<string, ex> sym_tab;
+typedef std::map<std::string, GiNaC::ex> sym_tab;
extern sym_tab syms;
// Type of symbols to generate (real or complex)
* functions. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
-#!/usr/bin/env python3
+
# encoding: utf-8
# Convert help for ginsh functions from man page to C source
import sys, re, optparse
* This file must be processed with flex. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "ginsh.h"
#include "ginsh_parser.hpp"
+using namespace std;
+using namespace GiNaC;
+
#define YY_INPUT(buf, result, max_size) (result = ginsh_input(buf, max_size))
// Table of all used symbols
YY_FATAL_ERROR("input in flex scanner failed");
result = n;
#endif
- } else if (((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin))
- YY_FATAL_ERROR("input in flex scanner failed");
+ } else {
+ int c = '*', n;
+ for (n = 0; n < max_size && (c = getc(yyin)) != EOF && c != '\n'; ++n)
+ buf[n] = (char)c;
+ if (c == '\n')
+ buf[n++] = (char)c;
+ if (c == EOF && ferror(yyin))
+ YY_FATAL_ERROR("input in flex scanner failed");
+ result = n;
+ }
return result;
}
-#!/usr/bin/env python3
+
# encoding: utf-8
# Convert help for ginsh operators from man page to C source
import sys, re, optparse
* This file must be processed with yacc/bison. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "ginsh.h"
+using namespace std;
+using namespace GiNaC;
+
#define YYERROR_VERBOSE 1
#ifdef HAVE_LIBREADLINE
static ex f_integral(const exprseq &e)
{
CHECK_ARG(0, symbol, integral);
- return integral(e[0], e[1], e[2], e[3]);
+ return GiNaC::integral(e[0], e[1], e[2], e[3]);
}
static ex f_inverse(const exprseq &e)
return e[0].series(e[1], ex_to<numeric>(e[2]).to_int());
}
+static ex f_series_to_poly(const exprseq &e)
+{
+ CHECK_ARG(0, pseries, series_to_poly);
+ return series_to_poly(ex_to<pseries>(e[0]));
+}
+
static ex f_sprem(const exprseq &e)
{
return sprem(e[0], e[1], e[2]);
return sqrfree(e[0], ex_to<lst>(e[1]));
}
+static ex f_sqrfree_parfrac(const exprseq &e)
+{
+ return sqrfree_parfrac(e[0], ex_to<symbol>(e[1]));
+}
+
static ex f_subs3(const exprseq &e)
{
CHECK_ARG(1, lst, subs);
return e[0].unit(e[1]);
}
+static ex f_basic_log_kernel(const exprseq &e)
+{
+ return basic_log_kernel();
+}
+
+static ex f_multiple_polylog_kernel(const exprseq &e)
+{
+ return multiple_polylog_kernel(e[0]);
+}
+
+static ex f_ELi_kernel(const exprseq &e)
+{
+ return ELi_kernel(e[0],e[1],e[2],e[3]);
+}
+
+static ex f_Ebar_kernel(const exprseq &e)
+{
+ return Ebar_kernel(e[0],e[1],e[2],e[3]);
+}
+
+static ex f_Kronecker_dtau_kernel_4(const exprseq &e)
+{
+ return Kronecker_dtau_kernel(e[0],e[1],e[2],e[3]);
+}
+
+static ex f_Kronecker_dtau_kernel_3(const exprseq &e)
+{
+ return Kronecker_dtau_kernel(e[0],e[1],e[2]);
+}
+
+static ex f_Kronecker_dtau_kernel_2(const exprseq &e)
+{
+ return Kronecker_dtau_kernel(e[0],e[1]);
+}
+
+static ex f_Kronecker_dz_kernel_5(const exprseq &e)
+{
+ return Kronecker_dz_kernel(e[0],e[1],e[2],e[3],e[4]);
+}
+
+static ex f_Kronecker_dz_kernel_4(const exprseq &e)
+{
+ return Kronecker_dz_kernel(e[0],e[1],e[2],e[3]);
+}
+
+static ex f_Kronecker_dz_kernel_3(const exprseq &e)
+{
+ return Kronecker_dz_kernel(e[0],e[1],e[2]);
+}
+
+static ex f_Eisenstein_kernel_6(const exprseq &e)
+{
+ return Eisenstein_kernel(e[0],e[1],e[2],e[3],e[4],e[5]);
+}
+
+static ex f_Eisenstein_kernel_5(const exprseq &e)
+{
+ return Eisenstein_kernel(e[0],e[1],e[2],e[3],e[4]);
+}
+
+static ex f_Eisenstein_h_kernel_5(const exprseq &e)
+{
+ return Eisenstein_h_kernel(e[0],e[1],e[2],e[3],e[4]);
+}
+
+static ex f_Eisenstein_h_kernel_4(const exprseq &e)
+{
+ return Eisenstein_h_kernel(e[0],e[1],e[2],e[3]);
+}
+
+static ex f_modular_form_kernel_3(const exprseq &e)
+{
+ return modular_form_kernel(e[0],e[1],e[2]);
+}
+
+static ex f_modular_form_kernel_2(const exprseq &e)
+{
+ return modular_form_kernel(e[0],e[1]);
+}
+
+static ex f_user_defined_kernel(const exprseq &e)
+{
+ return user_defined_kernel(e[0],e[1]);
+}
+
+static ex f_q_expansion_modular_form(const exprseq &e)
+{
+ if ( is_a<Eisenstein_kernel>(e[0]) ) {
+ return ex_to<Eisenstein_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int());
+ }
+ if ( is_a<Eisenstein_h_kernel>(e[0]) ) {
+ return ex_to<Eisenstein_h_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int());
+ }
+ if ( is_a<modular_form_kernel>(e[0]) ) {
+ return ex_to<modular_form_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int());
+ }
+ throw(std::invalid_argument("first argument must be a modular form"));
+}
+
static ex f_dummy(const exprseq &e)
{
throw(std::logic_error("dummy function called (shouldn't happen)"));
{"rem", f_rem, 3},
{"resultant", f_resultant, 3},
{"series", f_series, 3},
+ {"series_to_poly", f_series_to_poly, 1},
{"sprem", f_sprem, 3},
{"sqrfree", f_sqrfree1, 1},
{"sqrfree", f_sqrfree2, 2},
+ {"sqrfree_parfrac", f_sqrfree_parfrac, 2},
{"sqrt", f_sqrt, 1},
{"subs", f_subs2, 2},
{"subs", f_subs3, 3},
{"transpose", f_transpose, 1},
{"unassign", f_unassign, 1},
{"unit", f_unit, 2},
+ {"basic_log_kernel", f_basic_log_kernel, 0},
+ {"multiple_polylog_kernel", f_multiple_polylog_kernel, 1},
+ {"ELi_kernel", f_ELi_kernel, 4},
+ {"Ebar_kernel", f_Ebar_kernel, 4},
+ {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_4, 4},
+ {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_3, 3},
+ {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_2, 2},
+ {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_5, 5},
+ {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_4, 4},
+ {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_3, 3},
+ {"Eisenstein_kernel", f_Eisenstein_kernel_6, 6},
+ {"Eisenstein_kernel", f_Eisenstein_kernel_5, 5},
+ {"Eisenstein_h_kernel", f_Eisenstein_h_kernel_5, 5},
+ {"Eisenstein_h_kernel", f_Eisenstein_h_kernel_4, 4},
+ {"modular_form_kernel", f_modular_form_kernel_3, 3},
+ {"modular_form_kernel", f_modular_form_kernel_2, 2},
+ {"user_defined_kernel", f_user_defined_kernel, 2},
+ {"q_expansion_modular_form", f_q_expansion_modular_form, 3},
{nullptr, f_dummy, 0} // End marker
};
{"tan", "tangent function"},
{"tanh", "hyperbolic tangent function"},
{"zeta", "zeta function\nzeta(x) is Riemann's zeta function, zetaderiv(n,x) its nth derivative.\nIf x is a GiNaC::lst, it is a multiple zeta value\nzeta(x,s) is an alternating Euler sum"},
+ {"G", "multiple polylogarithm (integral representation)"},
{"Li2", "dilogarithm"},
{"Li3", "trilogarithm"},
{"Li", "(multiple) polylogarithm"},
{"S", "Nielsen's generalized polylogarithm"},
{"H", "harmonic polylogarithm"},
+ {"EllipticK", "complete elliptic integral of the first kind"},
+ {"EllipticE", "complete elliptic integral of the second kind"},
+ {"iterated_integral", "iterated integral"},
{"Order", "order term function (for truncated power series)"},
{"Derivative", "inert differential operator"},
{nullptr, nullptr} // End marker
void greeting(void)
{
cout << "ginsh - GiNaC Interactive Shell (GiNaC V" << GINACLIB_VERSION << ")" << endl;
- cout << " __, _______ Copyright (C) 1999-2019 Johannes Gutenberg University Mainz,\n"
+ cout << " __, _______ Copyright (C) 1999-2023 Johannes Gutenberg University Mainz,\n"
<< " (__) * | Germany. This is free software with ABSOLUTELY NO WARRANTY.\n"
<< " ._) i N a C | You are welcome to redistribute it under certain conditions.\n"
<< "<-------------' For details type `warranty;'.\n" << endl;
--- /dev/null
+libtool.m4
+ltoptions.m4
+ltsugar.m4
+ltversion.m4
+lt~obsolete.m4
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXX and
-# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
-# or '14' (for the C++14 standard).
+# CXXCPP to enable support. VERSION may be '11', '14', '17', or '20' for
+# the respective C++ standard version.
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
-# preference for an extended mode.
+# preference for no added switch, and then for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
+# Copyright (c) 2020 Jason Merrill <jason@redhat.com>
+# Copyright (c) 2021 Jörn Heusipp <osmanx@problemloesungsmaschine.de>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 11
+#serial 18
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+ [$1], [20], [ax_cxx_compile_alternatives="20"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
AC_LANG_PUSH([C++])dnl
ac_success=no
+ m4_if([$2], [], [dnl
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+ ax_cv_cxx_compile_cxx$1,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [ax_cv_cxx_compile_cxx$1=yes],
+ [ax_cv_cxx_compile_cxx$1=no])])
+ if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+ ac_success=yes
+ fi])
+
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for alternative in ${ax_cxx_compile_alternatives}; do
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
+ dnl MSVC needs -std:c++NN for C++17 and later (default is C++14)
for alternative in ${ax_cxx_compile_alternatives}; do
- for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do
+ if test x"$switch" = xMSVC; then
+ dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide
+ dnl with -std=c++17. We suffix the cache variable name with _MSVC to
+ dnl avoid this.
+ switch=-std:c++${alternative}
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC])
+ else
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ fi
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)
-
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
+dnl Test body for checking C++17 support
+
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
+dnl Test body for checking C++20 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_20
+)
+
+
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
#error "This is not a C++ compiler"
-#elif __cplusplus < 201103L
+// MSVC always sets __cplusplus to 199711L in older versions; newer versions
+// only set it correctly if /Zc:__cplusplus is specified as well as a
+// /std:c++NN switch:
+// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
+#elif __cplusplus < 201103L && !defined _MSC_VER
#error "This is not a C++11 compiler"
#error "This is not a C++ compiler"
-#elif __cplusplus < 201402L
+#elif __cplusplus < 201402L && !defined _MSC_VER
#error "This is not a C++14 compiler"
#error "This is not a C++ compiler"
-#elif __cplusplus < 201703L
+#elif __cplusplus < 201703L && !defined _MSC_VER
#error "This is not a C++17 compiler"
} // namespace cxx17
-#endif // __cplusplus < 201703L
+#endif // __cplusplus < 201703L && !defined _MSC_VER
+
+]])
+
+
+dnl Tests for new features in C++20
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 202002L && !defined _MSC_VER
+
+#error "This is not a C++20 compiler"
+
+#else
+
+#include <version>
+
+namespace cxx20
+{
+
+// As C++20 supports feature test macros in the standard, there is no
+// immediate need to actually test for feature availability on the
+// Autoconf side.
+
+} // namespace cxx20
+
+#endif // __cplusplus < 202002L && !defined _MSC_VER
]])
--- /dev/null
+# host-cpu-c-abi.m4 serial 15
+dnl Copyright (C) 2002-2023 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible and Sam Steingold.
+
+dnl Sets the HOST_CPU variable to the canonical name of the CPU.
+dnl Sets the HOST_CPU_C_ABI variable to the canonical name of the CPU with its
+dnl C language ABI (application binary interface).
+dnl Also defines __${HOST_CPU}__ and __${HOST_CPU_C_ABI}__ as C macros in
+dnl config.h.
+dnl
+dnl This canonical name can be used to select a particular assembly language
+dnl source file that will interoperate with C code on the given host.
+dnl
+dnl For example:
+dnl * 'i386' and 'sparc' are different canonical names, because code for i386
+dnl will not run on SPARC CPUs and vice versa. They have different
+dnl instruction sets.
+dnl * 'sparc' and 'sparc64' are different canonical names, because code for
+dnl 'sparc' and code for 'sparc64' cannot be linked together: 'sparc' code
+dnl contains 32-bit instructions, whereas 'sparc64' code contains 64-bit
+dnl instructions. A process on a SPARC CPU can be in 32-bit mode or in 64-bit
+dnl mode, but not both.
+dnl * 'mips' and 'mipsn32' are different canonical names, because they use
+dnl different argument passing and return conventions for C functions, and
+dnl although the instruction set of 'mips' is a large subset of the
+dnl instruction set of 'mipsn32'.
+dnl * 'mipsn32' and 'mips64' are different canonical names, because they use
+dnl different sizes for the C types like 'int' and 'void *', and although
+dnl the instruction sets of 'mipsn32' and 'mips64' are the same.
+dnl * The same canonical name is used for different endiannesses. You can
+dnl determine the endianness through preprocessor symbols:
+dnl - 'arm': test __ARMEL__.
+dnl - 'mips', 'mipsn32', 'mips64': test _MIPSEB vs. _MIPSEL.
+dnl - 'powerpc64': test _BIG_ENDIAN vs. _LITTLE_ENDIAN.
+dnl * The same name 'i386' is used for CPUs of type i386, i486, i586
+dnl (Pentium), AMD K7, Pentium II, Pentium IV, etc., because
+dnl - Instructions that do not exist on all of these CPUs (cmpxchg,
+dnl MMX, SSE, SSE2, 3DNow! etc.) are not frequently used. If your
+dnl assembly language source files use such instructions, you will
+dnl need to make the distinction.
+dnl - Speed of execution of the common instruction set is reasonable across
+dnl the entire family of CPUs. If you have assembly language source files
+dnl that are optimized for particular CPU types (like GNU gmp has), you
+dnl will need to make the distinction.
+dnl See <https://en.wikipedia.org/wiki/X86_instruction_listings>.
+AC_DEFUN([gl_HOST_CPU_C_ABI],
+[
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([gl_C_ASM])
+ AC_CACHE_CHECK([host CPU and C ABI], [gl_cv_host_cpu_c_abi],
+ [case "$host_cpu" in
+
+changequote(,)dnl
+ i[34567]86 )
+changequote([,])dnl
+ gl_cv_host_cpu_c_abi=i386
+ ;;
+
+ x86_64 )
+ # On x86_64 systems, the C compiler may be generating code in one of
+ # these ABIs:
+ # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64.
+ # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64
+ # with native Windows (mingw, MSVC).
+ # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32.
+ # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if (defined __x86_64__ || defined __amd64__ \
+ || defined _M_X64 || defined _M_AMD64)
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __ILP32__ || defined _ILP32
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=x86_64-x32],
+ [gl_cv_host_cpu_c_abi=x86_64])],
+ [gl_cv_host_cpu_c_abi=i386])
+ ;;
+
+changequote(,)dnl
+ alphaev[4-8] | alphaev56 | alphapca5[67] | alphaev6[78] )
+changequote([,])dnl
+ gl_cv_host_cpu_c_abi=alpha
+ ;;
+
+ arm* | aarch64 )
+ # Assume arm with EABI.
+ # On arm64 systems, the C compiler may be generating code in one of
+ # these ABIs:
+ # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64.
+ # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32.
+ # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#ifdef __aarch64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __ILP32__ || defined _ILP32
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=arm64-ilp32],
+ [gl_cv_host_cpu_c_abi=arm64])],
+ [# Don't distinguish little-endian and big-endian arm, since they
+ # don't require different machine code for simple operations and
+ # since the user can distinguish them through the preprocessor
+ # defines __ARMEL__ vs. __ARMEB__.
+ # But distinguish arm which passes floating-point arguments and
+ # return values in integer registers (r0, r1, ...) - this is
+ # gcc -mfloat-abi=soft or gcc -mfloat-abi=softfp - from arm which
+ # passes them in float registers (s0, s1, ...) and double registers
+ # (d0, d1, ...) - this is gcc -mfloat-abi=hard. GCC 4.6 or newer
+ # sets the preprocessor defines __ARM_PCS (for the first case) and
+ # __ARM_PCS_VFP (for the second case), but older GCC does not.
+ echo 'double ddd; void func (double dd) { ddd = dd; }' > conftest.c
+ # Look for a reference to the register d0 in the .s file.
+ AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $gl_c_asm_opt conftest.c) >/dev/null 2>&1
+ if LC_ALL=C grep 'd0,' conftest.$gl_asmext >/dev/null; then
+ gl_cv_host_cpu_c_abi=armhf
+ else
+ gl_cv_host_cpu_c_abi=arm
+ fi
+ rm -f conftest*
+ ])
+ ;;
+
+ hppa1.0 | hppa1.1 | hppa2.0* | hppa64 )
+ # On hppa, the C compiler may be generating 32-bit code or 64-bit
+ # code. In the latter case, it defines _LP64 and __LP64__.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#ifdef __LP64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=hppa64],
+ [gl_cv_host_cpu_c_abi=hppa])
+ ;;
+
+ ia64* )
+ # On ia64 on HP-UX, the C compiler may be generating 64-bit code or
+ # 32-bit code. In the latter case, it defines _ILP32.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#ifdef _ILP32
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=ia64-ilp32],
+ [gl_cv_host_cpu_c_abi=ia64])
+ ;;
+
+ mips* )
+ # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this
+ # at 32.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64)
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=mips64],
+ [# In the n32 ABI, _ABIN32 is defined, _ABIO32 is not defined (but
+ # may later get defined by <sgidefs.h>), and _MIPS_SIM == _ABIN32.
+ # In the 32 ABI, _ABIO32 is defined, _ABIN32 is not defined (but
+ # may later get defined by <sgidefs.h>), and _MIPS_SIM == _ABIO32.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if (_MIPS_SIM == _ABIN32)
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=mipsn32],
+ [gl_cv_host_cpu_c_abi=mips])])
+ ;;
+
+ powerpc* )
+ # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD.
+ # No need to distinguish them here; the caller may distinguish
+ # them based on the OS.
+ # On powerpc64 systems, the C compiler may still be generating
+ # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may
+ # be generating 64-bit code.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __powerpc64__ || defined __LP64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [# On powerpc64, there are two ABIs on Linux: The AIX compatible
+ # one and the ELFv2 one. The latter defines _CALL_ELF=2.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined _CALL_ELF && _CALL_ELF == 2
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=powerpc64-elfv2],
+ [gl_cv_host_cpu_c_abi=powerpc64])
+ ],
+ [gl_cv_host_cpu_c_abi=powerpc])
+ ;;
+
+ rs6000 )
+ gl_cv_host_cpu_c_abi=powerpc
+ ;;
+
+ riscv32 | riscv64 )
+ # There are 2 architectures (with variants): rv32* and rv64*.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if __riscv_xlen == 64
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [cpu=riscv64],
+ [cpu=riscv32])
+ # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d.
+ # Size of 'long' and 'void *':
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __LP64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [main_abi=lp64],
+ [main_abi=ilp32])
+ # Float ABIs:
+ # __riscv_float_abi_double:
+ # 'float' and 'double' are passed in floating-point registers.
+ # __riscv_float_abi_single:
+ # 'float' are passed in floating-point registers.
+ # __riscv_float_abi_soft:
+ # No values are passed in floating-point registers.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __riscv_float_abi_double
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [float_abi=d],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __riscv_float_abi_single
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [float_abi=f],
+ [float_abi=''])
+ ])
+ gl_cv_host_cpu_c_abi="${cpu}-${main_abi}${float_abi}"
+ ;;
+
+ s390* )
+ # On s390x, the C compiler may be generating 64-bit (= s390x) code
+ # or 31-bit (= s390) code.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __LP64__ || defined __s390x__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=s390x],
+ [gl_cv_host_cpu_c_abi=s390])
+ ;;
+
+ sparc | sparc64 )
+ # UltraSPARCs running Linux have `uname -m` = "sparc64", but the
+ # C compiler still generates 32-bit code.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __sparcv9 || defined __arch64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi=sparc64],
+ [gl_cv_host_cpu_c_abi=sparc])
+ ;;
+
+ *)
+ gl_cv_host_cpu_c_abi="$host_cpu"
+ ;;
+ esac
+ ])
+
+ dnl In most cases, $HOST_CPU and $HOST_CPU_C_ABI are the same.
+ HOST_CPU=`echo "$gl_cv_host_cpu_c_abi" | sed -e 's/-.*//'`
+ HOST_CPU_C_ABI="$gl_cv_host_cpu_c_abi"
+ AC_SUBST([HOST_CPU])
+ AC_SUBST([HOST_CPU_C_ABI])
+
+ # This was
+ # AC_DEFINE_UNQUOTED([__${HOST_CPU}__])
+ # AC_DEFINE_UNQUOTED([__${HOST_CPU_C_ABI}__])
+ # earlier, but KAI C++ 3.2d doesn't like this.
+ sed -e 's/-/_/g' >> confdefs.h <<EOF
+#ifndef __${HOST_CPU}__
+#define __${HOST_CPU}__ 1
+#endif
+#ifndef __${HOST_CPU_C_ABI}__
+#define __${HOST_CPU_C_ABI}__ 1
+#endif
+EOF
+ AH_TOP([/* CPU and C ABI indicator */
+#ifndef __i386__
+#undef __i386__
+#endif
+#ifndef __x86_64_x32__
+#undef __x86_64_x32__
+#endif
+#ifndef __x86_64__
+#undef __x86_64__
+#endif
+#ifndef __alpha__
+#undef __alpha__
+#endif
+#ifndef __arm__
+#undef __arm__
+#endif
+#ifndef __armhf__
+#undef __armhf__
+#endif
+#ifndef __arm64_ilp32__
+#undef __arm64_ilp32__
+#endif
+#ifndef __arm64__
+#undef __arm64__
+#endif
+#ifndef __hppa__
+#undef __hppa__
+#endif
+#ifndef __hppa64__
+#undef __hppa64__
+#endif
+#ifndef __ia64_ilp32__
+#undef __ia64_ilp32__
+#endif
+#ifndef __ia64__
+#undef __ia64__
+#endif
+#ifndef __loongarch64__
+#undef __loongarch64__
+#endif
+#ifndef __m68k__
+#undef __m68k__
+#endif
+#ifndef __mips__
+#undef __mips__
+#endif
+#ifndef __mipsn32__
+#undef __mipsn32__
+#endif
+#ifndef __mips64__
+#undef __mips64__
+#endif
+#ifndef __powerpc__
+#undef __powerpc__
+#endif
+#ifndef __powerpc64__
+#undef __powerpc64__
+#endif
+#ifndef __powerpc64_elfv2__
+#undef __powerpc64_elfv2__
+#endif
+#ifndef __riscv32__
+#undef __riscv32__
+#endif
+#ifndef __riscv64__
+#undef __riscv64__
+#endif
+#ifndef __riscv32_ilp32__
+#undef __riscv32_ilp32__
+#endif
+#ifndef __riscv32_ilp32f__
+#undef __riscv32_ilp32f__
+#endif
+#ifndef __riscv32_ilp32d__
+#undef __riscv32_ilp32d__
+#endif
+#ifndef __riscv64_ilp32__
+#undef __riscv64_ilp32__
+#endif
+#ifndef __riscv64_ilp32f__
+#undef __riscv64_ilp32f__
+#endif
+#ifndef __riscv64_ilp32d__
+#undef __riscv64_ilp32d__
+#endif
+#ifndef __riscv64_lp64__
+#undef __riscv64_lp64__
+#endif
+#ifndef __riscv64_lp64f__
+#undef __riscv64_lp64f__
+#endif
+#ifndef __riscv64_lp64d__
+#undef __riscv64_lp64d__
+#endif
+#ifndef __s390__
+#undef __s390__
+#endif
+#ifndef __s390x__
+#undef __s390x__
+#endif
+#ifndef __sh__
+#undef __sh__
+#endif
+#ifndef __sparc__
+#undef __sparc__
+#endif
+#ifndef __sparc64__
+#undef __sparc64__
+#endif
+])
+
+])
+
+
+dnl Sets the HOST_CPU_C_ABI_32BIT variable to 'yes' if the C language ABI
+dnl (application binary interface) is a 32-bit one, to 'no' if it is a 64-bit
+dnl one, or to 'unknown' if unknown.
+dnl This is a simplified variant of gl_HOST_CPU_C_ABI.
+AC_DEFUN([gl_HOST_CPU_C_ABI_32BIT],
+[
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_CACHE_CHECK([32-bit host C ABI], [gl_cv_host_cpu_c_abi_32bit],
+ [if test -n "$gl_cv_host_cpu_c_abi"; then
+ case "$gl_cv_host_cpu_c_abi" in
+ i386 | x86_64-x32 | arm | armhf | arm64-ilp32 | hppa | ia64-ilp32 | mips | mipsn32 | powerpc | riscv*-ilp32* | s390 | sparc)
+ gl_cv_host_cpu_c_abi_32bit=yes ;;
+ x86_64 | alpha | arm64 | hppa64 | ia64 | mips64 | powerpc64 | powerpc64-elfv2 | riscv*-lp64* | s390x | sparc64 )
+ gl_cv_host_cpu_c_abi_32bit=no ;;
+ *)
+ gl_cv_host_cpu_c_abi_32bit=unknown ;;
+ esac
+ else
+ case "$host_cpu" in
+
+ # CPUs that only support a 32-bit ABI.
+ arc \
+ | bfin \
+ | cris* \
+ | csky \
+ | epiphany \
+ | ft32 \
+ | h8300 \
+ | m68k \
+ | microblaze | microblazeel \
+ | nds32 | nds32le | nds32be \
+ | nios2 | nios2eb | nios2el \
+ | or1k* \
+ | or32 \
+ | sh | sh[1234] | sh[1234]e[lb] \
+ | tic6x \
+ | xtensa* )
+ gl_cv_host_cpu_c_abi_32bit=yes
+ ;;
+
+ # CPUs that only support a 64-bit ABI.
+changequote(,)dnl
+ alpha | alphaev[4-8] | alphaev56 | alphapca5[67] | alphaev6[78] \
+ | mmix )
+changequote([,])dnl
+ gl_cv_host_cpu_c_abi_32bit=no
+ ;;
+
+changequote(,)dnl
+ i[34567]86 )
+changequote([,])dnl
+ gl_cv_host_cpu_c_abi_32bit=yes
+ ;;
+
+ x86_64 )
+ # On x86_64 systems, the C compiler may be generating code in one of
+ # these ABIs:
+ # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64.
+ # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64
+ # with native Windows (mingw, MSVC).
+ # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32.
+ # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if (defined __x86_64__ || defined __amd64__ \
+ || defined _M_X64 || defined _M_AMD64) \
+ && !(defined __ILP32__ || defined _ILP32)
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=no],
+ [gl_cv_host_cpu_c_abi_32bit=yes])
+ ;;
+
+ arm* | aarch64 )
+ # Assume arm with EABI.
+ # On arm64 systems, the C compiler may be generating code in one of
+ # these ABIs:
+ # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64.
+ # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32.
+ # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __aarch64__ && !(defined __ILP32__ || defined _ILP32)
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=no],
+ [gl_cv_host_cpu_c_abi_32bit=yes])
+ ;;
+
+ hppa1.0 | hppa1.1 | hppa2.0* | hppa64 )
+ # On hppa, the C compiler may be generating 32-bit code or 64-bit
+ # code. In the latter case, it defines _LP64 and __LP64__.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#ifdef __LP64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=no],
+ [gl_cv_host_cpu_c_abi_32bit=yes])
+ ;;
+
+ ia64* )
+ # On ia64 on HP-UX, the C compiler may be generating 64-bit code or
+ # 32-bit code. In the latter case, it defines _ILP32.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#ifdef _ILP32
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=yes],
+ [gl_cv_host_cpu_c_abi_32bit=no])
+ ;;
+
+ mips* )
+ # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this
+ # at 32.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64)
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=no],
+ [gl_cv_host_cpu_c_abi_32bit=yes])
+ ;;
+
+ powerpc* )
+ # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD.
+ # No need to distinguish them here; the caller may distinguish
+ # them based on the OS.
+ # On powerpc64 systems, the C compiler may still be generating
+ # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may
+ # be generating 64-bit code.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __powerpc64__ || defined __LP64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=no],
+ [gl_cv_host_cpu_c_abi_32bit=yes])
+ ;;
+
+ rs6000 )
+ gl_cv_host_cpu_c_abi_32bit=yes
+ ;;
+
+ riscv32 | riscv64 )
+ # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d.
+ # Size of 'long' and 'void *':
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __LP64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=no],
+ [gl_cv_host_cpu_c_abi_32bit=yes])
+ ;;
+
+ s390* )
+ # On s390x, the C compiler may be generating 64-bit (= s390x) code
+ # or 31-bit (= s390) code.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __LP64__ || defined __s390x__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=no],
+ [gl_cv_host_cpu_c_abi_32bit=yes])
+ ;;
+
+ sparc | sparc64 )
+ # UltraSPARCs running Linux have `uname -m` = "sparc64", but the
+ # C compiler still generates 32-bit code.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __sparcv9 || defined __arch64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [gl_cv_host_cpu_c_abi_32bit=no],
+ [gl_cv_host_cpu_c_abi_32bit=yes])
+ ;;
+
+ *)
+ gl_cv_host_cpu_c_abi_32bit=unknown
+ ;;
+ esac
+ fi
+ ])
+
+ HOST_CPU_C_ABI_32BIT="$gl_cv_host_cpu_c_abi_32bit"
+])
-# lib-ld.m4 serial 6
-dnl Copyright (C) 1996-2003, 2009-2015 Free Software Foundation, Inc.
+# lib-ld.m4 serial 10
+dnl Copyright (C) 1996-2003, 2009-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
}
fi
-ac_prog=ld
-if test "$GCC" = yes; then
- # Check if gcc -print-prog-name=ld gives a path.
+if test -n "$LD"; then
+ AC_MSG_CHECKING([for ld])
+elif test "$GCC" = yes; then
AC_MSG_CHECKING([for ld used by $CC])
- case $host in
- *-*-mingw*)
- # gcc leaves a trailing carriage return which upsets mingw
- ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
- *)
- ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
- esac
- case $ac_prog in
- # Accept absolute paths.
- [[\\/]]* | ?:[[\\/]]*)
- re_direlt='/[[^/]][[^/]]*/\.\./'
- # Canonicalize the pathname of ld
- ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'`
- while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
- done
- test -z "$LD" && LD="$ac_prog"
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
elif test "$with_gnu_ld" = yes; then
AC_MSG_CHECKING([for GNU ld])
else
AC_MSG_CHECKING([for non-GNU ld])
fi
-AC_CACHE_VAL([acl_cv_path_LD],
-[if test -z "$LD"; then
- acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH; do
- IFS="$acl_save_ifs"
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- acl_cv_path_LD="$ac_dir/$ac_prog"
- # Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some variants of GNU ld only accept -v.
- # Break only if it was the GNU/non-GNU ld that we prefer.
- case `"$acl_cv_path_LD" -v 2>&1 </dev/null` in
- *GNU* | *'with BFD'*)
- test "$with_gnu_ld" != no && break
- ;;
- *)
- test "$with_gnu_ld" != yes && break
- ;;
+if test -n "$LD"; then
+ # Let the user override the test with a path.
+ :
+else
+ AC_CACHE_VAL([acl_cv_path_LD],
+ [
+ acl_cv_path_LD= # Final result of this test
+ ac_prog=ld # Program to search in $PATH
+ if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ acl_output=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ acl_output=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $acl_output in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ acl_output=`echo "$acl_output" | sed 's%\\\\%/%g'`
+ while echo "$acl_output" | grep "$re_direlt" > /dev/null 2>&1; do
+ acl_output=`echo $acl_output | sed "s%$re_direlt%/%"`
+ done
+ # Got the pathname. No search in PATH is needed.
+ acl_cv_path_LD="$acl_output"
+ ac_prog=
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
esac
fi
- done
- IFS="$acl_save_ifs"
-else
- acl_cv_path_LD="$LD" # Let the user override the test with a path.
-fi])
-LD="$acl_cv_path_LD"
+ if test -n "$ac_prog"; then
+ # Search for $ac_prog in $PATH.
+ acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$acl_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ acl_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$acl_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$acl_save_ifs"
+ fi
+ case $host in
+ *-*-aix*)
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __powerpc64__ || defined __LP64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [# The compiler produces 64-bit code. Add option '-b64' so that the
+ # linker groks 64-bit object files.
+ case "$acl_cv_path_LD " in
+ *" -b64 "*) ;;
+ *) acl_cv_path_LD="$acl_cv_path_LD -b64" ;;
+ esac
+ ], [])
+ ;;
+ sparc64-*-netbsd*)
+ AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#if defined __sparcv9 || defined __arch64__
+ int ok;
+ #else
+ error fail
+ #endif
+ ]])],
+ [],
+ [# The compiler produces 32-bit code. Add option '-m elf32_sparc'
+ # so that the linker groks 32-bit object files.
+ case "$acl_cv_path_LD " in
+ *" -m elf32_sparc "*) ;;
+ *) acl_cv_path_LD="$acl_cv_path_LD -m elf32_sparc" ;;
+ esac
+ ])
+ ;;
+ esac
+ ])
+ LD="$acl_cv_path_LD"
+fi
if test -n "$LD"; then
AC_MSG_RESULT([$LD])
else
AC_MSG_RESULT([no])
+ AC_MSG_ERROR([no acceptable ld found in \$PATH])
fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
AC_LIB_PROG_LD_GNU
])
-# lib-link.m4 serial 26 (gettext-0.18.2)
-dnl Copyright (C) 2001-2015 Free Software Foundation, Inc.
+# lib-link.m4 serial 33
+dnl Copyright (C) 2001-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Bruno Haible.
-AC_PREREQ([2.54])
+AC_PREREQ([2.61])
dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
dnl the libraries corresponding to explicit and implicit dependencies.
dnl acl_hardcode_minus_L.
AC_DEFUN([AC_LIB_RPATH],
[
- dnl Tell automake >= 1.10 to complain if config.rpath is missing.
- m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
+ dnl Complain if config.rpath is missing.
+ AC_REQUIRE_AUX_FILE([config.rpath])
AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS
AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld
AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host
pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-],
[ABCDEFGHIJKLMNOPQRSTUVWXYZ____])])
pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])])
- dnl Autoconf >= 2.61 supports dots in --with options.
- pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[m4_translit(PACK,[.],[_])],PACK)])
dnl By default, look in $includedir and $libdir.
use_additional=yes
AC_LIB_WITH_FINAL_PREFIX([
eval additional_includedir=\"$includedir\"
eval additional_libdir=\"$libdir\"
+ eval additional_libdir2=\"$exec_prefix/$acl_libdirstem2\"
+ eval additional_libdir3=\"$exec_prefix/$acl_libdirstem3\"
])
- AC_ARG_WITH(P_A_C_K[-prefix],
-[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib
- --without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]],
+ AC_ARG_WITH(PACK[-prefix],
+[[ --with-]]PACK[[-prefix[=DIR] search for ]]PACKLIBS[[ in DIR/include and DIR/lib
+ --without-]]PACK[[-prefix don't search for ]]PACKLIBS[[ in includedir and libdir]],
[
if test "X$withval" = "Xno"; then
use_additional=no
AC_LIB_WITH_FINAL_PREFIX([
eval additional_includedir=\"$includedir\"
eval additional_libdir=\"$libdir\"
+ eval additional_libdir2=\"$exec_prefix/$acl_libdirstem2\"
+ eval additional_libdir3=\"$exec_prefix/$acl_libdirstem3\"
])
else
additional_includedir="$withval/include"
additional_libdir="$withval/$acl_libdirstem"
- if test "$acl_libdirstem2" != "$acl_libdirstem" \
- && ! test -d "$withval/$acl_libdirstem"; then
- additional_libdir="$withval/$acl_libdirstem2"
- fi
+ additional_libdir2="$withval/$acl_libdirstem2"
+ additional_libdir3="$withval/$acl_libdirstem3"
fi
fi
])
+ if test "X$additional_libdir2" = "X$additional_libdir"; then
+ additional_libdir2=
+ fi
+ if test "X$additional_libdir3" = "X$additional_libdir"; then
+ additional_libdir3=
+ fi
dnl Search the library and its dependencies in $additional_libdir and
- dnl $LDFLAGS. Using breadth-first-seach.
+ dnl $LDFLAGS. Use breadth-first search.
LIB[]NAME=
LTLIB[]NAME=
INC[]NAME=
shrext=
fi
if test $use_additional = yes; then
- dir="$additional_libdir"
- dnl The same code as in the loop below:
- dnl First look for a shared library.
- if test -n "$acl_shlibext"; then
- if test -f "$dir/$libname$shrext"; then
- found_dir="$dir"
- found_so="$dir/$libname$shrext"
- else
- if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
- ver=`(cd "$dir" && \
- for f in "$libname$shrext".*; do echo "$f"; done \
- | sed -e "s,^$libname$shrext\\\\.,," \
- | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
- | sed 1q ) 2>/dev/null`
- if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
- found_dir="$dir"
- found_so="$dir/$libname$shrext.$ver"
+ for additional_libdir_variable in additional_libdir additional_libdir2 additional_libdir3; do
+ if test "X$found_dir" = "X"; then
+ eval dir=\$$additional_libdir_variable
+ if test -n "$dir"; then
+ dnl The same code as in the loop below:
+ dnl First look for a shared library.
+ if test -n "$acl_shlibext"; then
+ if test -f "$dir/$libname$shrext" && acl_is_expected_elfclass < "$dir/$libname$shrext"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext"
+ else
+ if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+ ver=`(cd "$dir" && \
+ for f in "$libname$shrext".*; do echo "$f"; done \
+ | sed -e "s,^$libname$shrext\\\\.,," \
+ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+ | sed 1q ) 2>/dev/null`
+ if test -n "$ver" && test -f "$dir/$libname$shrext.$ver" && acl_is_expected_elfclass < "$dir/$libname$shrext.$ver"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext.$ver"
+ fi
+ else
+ eval library_names=\"$acl_library_names_spec\"
+ for f in $library_names; do
+ if test -f "$dir/$f" && acl_is_expected_elfclass < "$dir/$f"; then
+ found_dir="$dir"
+ found_so="$dir/$f"
+ break
+ fi
+ done
+ fi
+ fi
fi
- else
- eval library_names=\"$acl_library_names_spec\"
- for f in $library_names; do
- if test -f "$dir/$f"; then
+ dnl Then look for a static library.
+ if test "X$found_dir" = "X"; then
+ if test -f "$dir/$libname.$acl_libext" && ${AR-ar} -p "$dir/$libname.$acl_libext" | acl_is_expected_elfclass; then
found_dir="$dir"
- found_so="$dir/$f"
- break
+ found_a="$dir/$libname.$acl_libext"
fi
- done
+ fi
+ if test "X$found_dir" != "X"; then
+ if test -f "$dir/$libname.la"; then
+ found_la="$dir/$libname.la"
+ fi
+ fi
fi
fi
- fi
- dnl Then look for a static library.
- if test "X$found_dir" = "X"; then
- if test -f "$dir/$libname.$acl_libext"; then
- found_dir="$dir"
- found_a="$dir/$libname.$acl_libext"
- fi
- fi
- if test "X$found_dir" != "X"; then
- if test -f "$dir/$libname.la"; then
- found_la="$dir/$libname.la"
- fi
- fi
+ done
fi
if test "X$found_dir" = "X"; then
for x in $LDFLAGS $LTLIB[]NAME; do
dir=`echo "X$x" | sed -e 's/^X-L//'`
dnl First look for a shared library.
if test -n "$acl_shlibext"; then
- if test -f "$dir/$libname$shrext"; then
+ if test -f "$dir/$libname$shrext" && acl_is_expected_elfclass < "$dir/$libname$shrext"; then
found_dir="$dir"
found_so="$dir/$libname$shrext"
else
| sed -e "s,^$libname$shrext\\\\.,," \
| sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
| sed 1q ) 2>/dev/null`
- if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+ if test -n "$ver" && test -f "$dir/$libname$shrext.$ver" && acl_is_expected_elfclass < "$dir/$libname$shrext.$ver"; then
found_dir="$dir"
found_so="$dir/$libname$shrext.$ver"
fi
else
eval library_names=\"$acl_library_names_spec\"
for f in $library_names; do
- if test -f "$dir/$f"; then
+ if test -f "$dir/$f" && acl_is_expected_elfclass < "$dir/$f"; then
found_dir="$dir"
found_so="$dir/$f"
break
fi
dnl Then look for a static library.
if test "X$found_dir" = "X"; then
- if test -f "$dir/$libname.$acl_libext"; then
+ if test -f "$dir/$libname.$acl_libext" && ${AR-ar} -p "$dir/$libname.$acl_libext" | acl_is_expected_elfclass; then
found_dir="$dir"
found_a="$dir/$libname.$acl_libext"
fi
dnl standard /usr/lib.
if test "$enable_rpath" = no \
|| test "X$found_dir" = "X/usr/$acl_libdirstem" \
- || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then
+ || test "X$found_dir" = "X/usr/$acl_libdirstem2" \
+ || test "X$found_dir" = "X/usr/$acl_libdirstem3"; then
dnl No hardcoding is needed.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
else
fi
additional_includedir="$basedir/include"
;;
+ */$acl_libdirstem3 | */$acl_libdirstem3/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem3/"'*$,,'`
+ if test "$name" = '$1'; then
+ LIB[]NAME[]_PREFIX="$basedir"
+ fi
+ additional_includedir="$basedir/include"
+ ;;
esac
if test "X$additional_includedir" != "X"; then
dnl Potentially add $additional_includedir to $INCNAME.
for dep in $dependency_libs; do
case "$dep" in
-L*)
- additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
- dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+ dependency_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ dnl Potentially add $dependency_libdir to $LIBNAME and $LTLIBNAME.
dnl But don't add it
dnl 1. if it's the standard /usr/lib,
dnl 2. if it's /usr/local/lib and we are using GCC on Linux,
dnl 3. if it's already present in $LDFLAGS or the already
dnl constructed $LIBNAME,
dnl 4. if it doesn't exist as a directory.
- if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \
- && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then
+ if test "X$dependency_libdir" != "X/usr/$acl_libdirstem" \
+ && test "X$dependency_libdir" != "X/usr/$acl_libdirstem2" \
+ && test "X$dependency_libdir" != "X/usr/$acl_libdirstem3"; then
haveit=
- if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \
- || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then
+ if test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem" \
+ || test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem2" \
+ || test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem3"; then
if test -n "$GCC"; then
case $host_os in
linux* | gnu* | k*bsd*-gnu) haveit=yes;;
haveit=
for x in $LDFLAGS $LIB[]NAME; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
- if test "X$x" = "X-L$additional_libdir"; then
+ if test "X$x" = "X-L$dependency_libdir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
- if test -d "$additional_libdir"; then
- dnl Really add $additional_libdir to $LIBNAME.
- LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+ if test -d "$dependency_libdir"; then
+ dnl Really add $dependency_libdir to $LIBNAME.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$dependency_libdir"
fi
fi
haveit=
for x in $LDFLAGS $LTLIB[]NAME; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
- if test "X$x" = "X-L$additional_libdir"; then
+ if test "X$x" = "X-L$dependency_libdir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
- if test -d "$additional_libdir"; then
- dnl Really add $additional_libdir to $LTLIBNAME.
- LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+ if test -d "$dependency_libdir"; then
+ dnl Really add $dependency_libdir to $LTLIBNAME.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$dependency_libdir"
fi
fi
fi
;;
-l*)
dnl Handle this in the next round.
- names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ dnl But on GNU systems, ignore -lc options, because
+ dnl - linking with libc is the default anyway,
+ dnl - linking with libc.a may produce an error
+ dnl "/usr/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie"
+ dnl or may produce an executable that always crashes, see
+ dnl <https://lists.gnu.org/archive/html/grep-devel/2020-09/msg00052.html>.
+ dep=`echo "X$dep" | sed -e 's/^X-l//'`
+ if test "X$dep" != Xc \
+ || case $host_os in
+ linux* | gnu* | k*bsd*-gnu) false ;;
+ *) true ;;
+ esac; then
+ names_next_round="$names_next_round $dep"
+ fi
;;
*.la)
dnl Handle this in the next round. Throw away the .la's
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
done
fi
- popdef([P_A_C_K])
popdef([PACKLIBS])
popdef([PACKUP])
popdef([PACK])
dir="$next"
dnl No need to hardcode the standard /usr/lib.
if test "X$dir" != "X/usr/$acl_libdirstem" \
- && test "X$dir" != "X/usr/$acl_libdirstem2"; then
+ && test "X$dir" != "X/usr/$acl_libdirstem2" \
+ && test "X$dir" != "X/usr/$acl_libdirstem3"; then
rpathdirs="$rpathdirs $dir"
fi
next=
-L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'`
dnl No need to hardcode the standard /usr/lib.
if test "X$dir" != "X/usr/$acl_libdirstem" \
- && test "X$dir" != "X/usr/$acl_libdirstem2"; then
+ && test "X$dir" != "X/usr/$acl_libdirstem2" \
+ && test "X$dir" != "X/usr/$acl_libdirstem3"; then
rpathdirs="$rpathdirs $dir"
fi
next= ;;
-# lib-prefix.m4 serial 7 (gettext-0.18)
-dnl Copyright (C) 2001-2005, 2008-2015 Free Software Foundation, Inc.
+# lib-prefix.m4 serial 20
+dnl Copyright (C) 2001-2005, 2008-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Bruno Haible.
-dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
-dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
-dnl require excessive bracketing.
-ifdef([AC_HELP_STRING],
-[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
-[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
-
dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
dnl to access previously installed libraries. The basic assumption is that
dnl a user will want packages to use other packages he previously installed
eval additional_includedir=\"$includedir\"
eval additional_libdir=\"$libdir\"
])
- AC_LIB_ARG_WITH([lib-prefix],
-[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
- --without-lib-prefix don't search for libraries in includedir and libdir],
+ AC_ARG_WITH([lib-prefix],
+[[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+ --without-lib-prefix don't search for libraries in includedir and libdir]],
[
if test "X$withval" = "Xno"; then
use_additional=no
])
dnl AC_LIB_PREPARE_MULTILIB creates
-dnl - a variable acl_libdirstem, containing the basename of the libdir, either
-dnl "lib" or "lib64" or "lib/64",
-dnl - a variable acl_libdirstem2, as a secondary possible value for
-dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or
-dnl "lib/amd64".
+dnl - a function acl_is_expected_elfclass, that tests whether standard input
+dn; has a 32-bit or 64-bit ELF header, depending on the host CPU ABI,
+dnl - 3 variables acl_libdirstem, acl_libdirstem2, acl_libdirstem3, containing
+dnl the basename of the libdir to try in turn, either "lib" or "lib64" or
+dnl "lib/64" or "lib32" or "lib/sparcv9" or "lib/amd64" or similar.
AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
[
- dnl There is no formal standard regarding lib and lib64.
- dnl On glibc systems, the current practice is that on a system supporting
+ dnl There is no formal standard regarding lib, lib32, and lib64.
+ dnl On most glibc systems, the current practice is that on a system supporting
dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
- dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine
- dnl the compiler's default mode by looking at the compiler's library search
- dnl path. If at least one of its elements ends in /lib64 or points to a
- dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI.
- dnl Otherwise we use the default, namely "lib".
+ dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. However, on
+ dnl Arch Linux based distributions, it's the opposite: 32-bit libraries go
+ dnl under $prefix/lib32 and 64-bit libraries go under $prefix/lib.
+ dnl We determine the compiler's default mode by looking at the compiler's
+ dnl library search path. If at least one of its elements ends in /lib64 or
+ dnl points to a directory whose absolute pathname ends in /lib64, we use that
+ dnl for 64-bit ABIs. Similarly for 32-bit ABIs. Otherwise we use the default,
+ dnl namely "lib".
dnl On Solaris systems, the current practice is that on a system supporting
dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or
dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib.
AC_REQUIRE([AC_CANONICAL_HOST])
- acl_libdirstem=lib
- acl_libdirstem2=
- case "$host_os" in
- solaris*)
- dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment
- dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>.
- dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link."
- dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the
- dnl symlink is missing, so we set acl_libdirstem2 too.
- AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit],
- [AC_EGREP_CPP([sixtyfour bits], [
-#ifdef _LP64
-sixtyfour bits
-#endif
- ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no])
- ])
- if test $gl_cv_solaris_64bit = yes; then
- acl_libdirstem=lib/64
- case "$host_cpu" in
- sparc*) acl_libdirstem2=lib/sparcv9 ;;
- i*86 | x86_64) acl_libdirstem2=lib/amd64 ;;
- esac
- fi
- ;;
- *)
- searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
- if test -n "$searchpath"; then
- acl_save_IFS="${IFS= }"; IFS=":"
- for searchdir in $searchpath; do
- if test -d "$searchdir"; then
- case "$searchdir" in
- */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
- */../ | */.. )
- # Better ignore directories of this form. They are misleading.
- ;;
- *) searchdir=`cd "$searchdir" && pwd`
- case "$searchdir" in
- */lib64 ) acl_libdirstem=lib64 ;;
- esac ;;
- esac
- fi
- done
- IFS="$acl_save_IFS"
- fi
- ;;
- esac
- test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
+ AC_REQUIRE([gl_HOST_CPU_C_ABI_32BIT])
+
+ AC_CACHE_CHECK([for ELF binary format], [gl_cv_elf],
+ [AC_EGREP_CPP([Extensible Linking Format],
+ [#if defined __ELF__ || (defined __linux__ && defined __EDG__)
+ Extensible Linking Format
+ #endif
+ ],
+ [gl_cv_elf=yes],
+ [gl_cv_elf=no])
+ ])
+ if test $gl_cv_elf = yes; then
+ # Extract the ELF class of a file (5th byte) in decimal.
+ # Cf. https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
+ if od -A x < /dev/null >/dev/null 2>/dev/null; then
+ # Use POSIX od.
+ func_elfclass ()
+ {
+ od -A n -t d1 -j 4 -N 1
+ }
+ else
+ # Use BSD hexdump.
+ func_elfclass ()
+ {
+ dd bs=1 count=1 skip=4 2>/dev/null | hexdump -e '1/1 "%3d "'
+ echo
+ }
+ fi
+ # Use 'expr', not 'test', to compare the values of func_elfclass, because on
+ # Solaris 11 OpenIndiana and Solaris 11 OmniOS, the result is 001 or 002,
+ # not 1 or 2.
+changequote(,)dnl
+ case $HOST_CPU_C_ABI_32BIT in
+ yes)
+ # 32-bit ABI.
+ acl_is_expected_elfclass ()
+ {
+ expr "`func_elfclass | sed -e 's/[ ]//g'`" = 1 > /dev/null
+ }
+ ;;
+ no)
+ # 64-bit ABI.
+ acl_is_expected_elfclass ()
+ {
+ expr "`func_elfclass | sed -e 's/[ ]//g'`" = 2 > /dev/null
+ }
+ ;;
+ *)
+ # Unknown.
+ acl_is_expected_elfclass ()
+ {
+ :
+ }
+ ;;
+ esac
+changequote([,])dnl
+ else
+ acl_is_expected_elfclass ()
+ {
+ :
+ }
+ fi
+
+ dnl Allow the user to override the result by setting acl_cv_libdirstems.
+ AC_CACHE_CHECK([for the common suffixes of directories in the library search path],
+ [acl_cv_libdirstems],
+ [dnl Try 'lib' first, because that's the default for libdir in GNU, see
+ dnl <https://www.gnu.org/prep/standards/html_node/Directory-Variables.html>.
+ acl_libdirstem=lib
+ acl_libdirstem2=
+ acl_libdirstem3=
+ case "$host_os" in
+ solaris*)
+ dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment
+ dnl <https://docs.oracle.com/cd/E19253-01/816-5138/dev-env/index.html>.
+ dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link."
+ dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the
+ dnl symlink is missing, so we set acl_libdirstem2 too.
+ if test $HOST_CPU_C_ABI_32BIT = no; then
+ acl_libdirstem2=lib/64
+ case "$host_cpu" in
+ sparc*) acl_libdirstem3=lib/sparcv9 ;;
+ i*86 | x86_64) acl_libdirstem3=lib/amd64 ;;
+ esac
+ fi
+ ;;
+ *)
+ dnl If $CC generates code for a 32-bit ABI, the libraries are
+ dnl surely under $prefix/lib or $prefix/lib32, not $prefix/lib64.
+ dnl Similarly, if $CC generates code for a 64-bit ABI, the libraries
+ dnl are surely under $prefix/lib or $prefix/lib64, not $prefix/lib32.
+ dnl Find the compiler's search path. However, non-system compilers
+ dnl sometimes have odd library search paths. But we can't simply invoke
+ dnl '/usr/bin/gcc -print-search-dirs' because that would not take into
+ dnl account the -m32/-m31 or -m64 options from the $CC or $CFLAGS.
+ searchpath=`(LC_ALL=C $CC $CPPFLAGS $CFLAGS -print-search-dirs) 2>/dev/null \
+ | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
+ if test $HOST_CPU_C_ABI_32BIT != no; then
+ # 32-bit or unknown ABI.
+ if test -d /usr/lib32; then
+ acl_libdirstem2=lib32
+ fi
+ fi
+ if test $HOST_CPU_C_ABI_32BIT != yes; then
+ # 64-bit or unknown ABI.
+ if test -d /usr/lib64; then
+ acl_libdirstem3=lib64
+ fi
+ fi
+ if test -n "$searchpath"; then
+ acl_save_IFS="${IFS= }"; IFS=":"
+ for searchdir in $searchpath; do
+ if test -d "$searchdir"; then
+ case "$searchdir" in
+ */lib32/ | */lib32 ) acl_libdirstem2=lib32 ;;
+ */lib64/ | */lib64 ) acl_libdirstem3=lib64 ;;
+ */../ | */.. )
+ # Better ignore directories of this form. They are misleading.
+ ;;
+ *) searchdir=`cd "$searchdir" && pwd`
+ case "$searchdir" in
+ */lib32 ) acl_libdirstem2=lib32 ;;
+ */lib64 ) acl_libdirstem3=lib64 ;;
+ esac ;;
+ esac
+ fi
+ done
+ IFS="$acl_save_IFS"
+ if test $HOST_CPU_C_ABI_32BIT = yes; then
+ # 32-bit ABI.
+ acl_libdirstem3=
+ fi
+ if test $HOST_CPU_C_ABI_32BIT = no; then
+ # 64-bit ABI.
+ acl_libdirstem2=
+ fi
+ fi
+ ;;
+ esac
+ test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
+ test -n "$acl_libdirstem3" || acl_libdirstem3="$acl_libdirstem"
+ acl_cv_libdirstems="$acl_libdirstem,$acl_libdirstem2,$acl_libdirstem3"
+ ])
+ dnl Decompose acl_cv_libdirstems into acl_libdirstem, acl_libdirstem2, and
+ dnl acl_libdirstem3.
+changequote(,)dnl
+ acl_libdirstem=`echo "$acl_cv_libdirstems" | sed -e 's/,.*//'`
+ acl_libdirstem2=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,//' -e 's/,.*//'`
+ acl_libdirstem3=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,[^,]*,//' -e 's/,.*//'`
+changequote([,])dnl
])
+++ /dev/null
-#!/usr/bin/env python3
-# encoding: utf-8
-# TeX Live 2012 seems to dislike files produces by doxygen (1.8.x.y)
-# In particular, makeindex(1) program creates invalid index entries like
-# \hyperpage{NNN_}
-# (note the trailing underscore in the page number). This breaks automatic
-# builds and is very annoying. Hence this script. It replaces (broken)
-# \hyperpage{NNN_} with \hyperpage{NNN}.
-# Note: this is an ugly work around, a proper fix is welcome.
-import sys, os, re
-
-def fixupind(fname):
- """ Fix \\hyperpage{NNN_} entries in the ind file @var{fname} """
- tmpout = fname + '.tmp'
- inp = open(fname)
- out = open(tmpout, 'wt')
- rx = re.compile('(hyperpage)[{]([0-9]+)[_][}]')
- for line in inp:
- out.write(re.sub(rx, '\\1{\\2}', line))
- out.flush()
- out.close()
- inp.close()
- os.rename(tmpout, fname)
-
-if __name__ == '__main__':
- if len(sys.argv) <= 1:
- sys.exit(1)
- fixupind(sys.argv[1])
- sys.exit(0)
-
-#!/usr/bin/env python3
+
"""
Yet Another Python Templating Utility, Version 1.2, by Alex Martelli.
Distributed under PSF license (http://docs.python.org/license.html).
--- /dev/null
+viewgar
+viewgar.1
+ginac-excompiler
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../ginac)
-add_definitions(-DIN_GINAC)
add_executable(viewgar viewgar.cpp)
-target_link_libraries(viewgar ginac ${LIBDL_LIBRARIES})
-install(TARGETS viewgar RUNTIME DESTINATION "${BIN_INSTALL_DIR}")
+target_link_libraries(viewgar ginac::ginac)
+install(TARGETS viewgar RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
if (CMAKE_COMPILER_IS_GNUCC)
set (CC gcc)
"${CMAKE_CURRENT_BINARY_DIR}/ginac-excompiler"
)
- install(PROGRAMS ginac-excompiler DESTINATION "${LIBEXECDIR}")
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/ginac-excompiler DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}")
endif (CMAKE_COMPILER_IS_GNUCC)
print raw dump of archive instead of formatted expressions
.SH AUTHOR
.TP
-The GiNaC Group:
-.br
-Christian Bauer <Christian.Bauer@uni-mainz.de>
-.br
-Alexander Frink <Alexander.Frink@uni-mainz.de>
-.br
-Richard Kreckel <Richard.Kreckel@uni-mainz.de>
-.br
-Jens Vollinga <vollinga@thep.physik.uni-mainz.de>
+The GiNaC maintainers <https://www.ginac.de/>.
.SH SEE ALSO
GiNaC Tutorial \- An open framework for symbolic computation within the
C++ programming language
.SH COPYRIGHT
-Copyright \(co 1999-2019 Johannes Gutenberg Universit\(:at Mainz, Germany
+Copyright \(co 1999-2023 Johannes Gutenberg Universit\(:at Mainz, Germany
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
* GiNaC archive file viewer. */
/*
- * GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by