diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index f779c166..4ac0d58c 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -1,4 +1,4 @@ -name: Build wheels +name: Distribution on: push: @@ -11,131 +11,79 @@ concurrency: cancel-in-progress: true jobs: - - sdists_for_pypi: - name: Build sdist (and upload to PyPI on release tags) + make_sdist: + name: Build sdist runs-on: ubuntu-latest - env: - CAN_DEPLOY: ${{ secrets.SAGEMATH_PYPI_API_TOKEN != '' }} steps: - uses: actions/checkout@v4 - - name: Install pari - run: | - bash -x .install-pari.sh - env: - PARI_VERSION: pari-2.17.1 - URLDIR: unix - - uses: actions/setup-python@v4 - - name: make sdist - run: | - python3 -m pip install build - python3 -m build --sdist + - uses: astral-sh/setup-uv@v6 + - name: Install PARI + run: ./.install-pari.sh + - name: Build sdist + run: uv build --sdist - uses: actions/upload-artifact@v4 with: - path: "dist/*.tar.gz" - name: dist-ubuntu-latest - - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.SAGEMATH_PYPI_API_TOKEN }} - skip_existing: true - verbose: true - if: env.CAN_DEPLOY == 'true' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + path: "dist/*.tar.*" + name: release-sdist build_wheels: - name: Build wheels on ${{ matrix.os }}, arch ${{ matrix.arch }} + name: Build wheels on ${{ matrix.os }} runs-on: ${{ matrix.os }} - needs: sdists_for_pypi strategy: fail-fast: false matrix: - include: - - os: ubuntu-latest - arch: x86_64 - - os: ubuntu-latest - arch: i686 - - os: macos-latest - arch: auto - - os: macos-14 - arch: auto - env: - # SPKGs to install as system packages - SPKGS: _bootstrap _prereq - # Non-Python packages to install as spkgs - TARGETS_PRE: pari - # Disable building PyPy wheels on all platforms - # Disable musllinux until #33083 provides alpine package information - CIBW_SKIP: "pp* *-musllinux*" - # - CIBW_ARCHS: ${{ matrix.arch }} - # https://cibuildwheel.readthedocs.io/en/stable/options/#requires-python - CIBW_PROJECT_REQUIRES_PYTHON: ">=3.10" - # Environment during wheel build - CIBW_ENVIRONMENT: "PATH=$(pwd)/local/bin:$PATH CPATH=$(pwd)/local/include:$CPATH LIBRARY_PATH=$(pwd)/local/lib:$LIBRARY_PATH LD_LIBRARY_PATH=$(pwd)/local/lib:$LD_LIBRARY_PATH PKG_CONFIG_PATH=$(pwd)/local/share/pkgconfig:$PKG_CONFIG_PATH ACLOCAL_PATH=/usr/share/aclocal" - # Use 'build', not 'pip wheel' - CIBW_BUILD_FRONTEND: build + os: + - ubuntu-latest + - ubuntu-24.04-arm + - windows-latest + - windows-11-arm + - macos-13 + - macos-latest steps: - uses: actions/checkout@v4 - with: - repository: sagemath/sage - ref: develop - - - uses: actions/download-artifact@v4 - with: - pattern: dist-* - path: dist - - - uses: actions/setup-python@v5 - # As of 2024-02-03, the macOS M1 runners do not have preinstalled python or pipx. - # Installing pipx follows the approach of https://github.com/pypa/cibuildwheel/pull/1743 - id: python - with: - python-version: "3.10 - 3.12" - update-environment: false - - - name: Build platform wheels - # We build the wheel from the sdist. - # But we must run cibuildwheel with the unpacked source directory, not a tarball, - # so that SAGE_ROOT is copied into the build containers. - # - # In the CIBW_BEFORE_ALL phase, we install libraries using the Sage distribution. - # https://cibuildwheel.readthedocs.io/en/stable/options/#before-all - run: | - "${{ steps.python.outputs.python-path }}" -m pip install pipx - export PATH=build/bin:$PATH - export CIBW_BEFORE_ALL="( $(sage-print-system-package-command debian --yes --no-install-recommends install $(sage-get-system-packages debian $SPKGS)) || $(sage-print-system-package-command fedora --yes --no-install-recommends install $(sage-get-system-packages fedora $SPKGS | sed s/pkg-config/pkgconfig/)) || ( $(sage-print-system-package-command homebrew --yes --no-install-recommends install $(sage-get-system-packages homebrew $SPKGS)) || echo error ignored) ) && ./bootstrap && ./configure --enable-build-as-root && make -j4 V=0 $TARGETS_PRE" - mkdir -p unpacked - for pkg in cypari2; do - (cd unpacked && tar xfz - ) < dist/dist-ubuntu-latest/$pkg*.tar.gz - "${{ steps.python.outputs.python-path }}" -m pipx run cibuildwheel==2.17.0 unpacked/$pkg* - done - + - uses: astral-sh/setup-uv@v6 + - name: Build wheels + uses: pypa/cibuildwheel@v3.1 + env: + CIBW_PROJECT_REQUIRES_PYTHON: ">=3.12, <3.14" + MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-latest' && '15.0' || '13.0' }} - uses: actions/upload-artifact@v4 with: - name: wheels-${{ matrix.os }}-${{ matrix.arch }} - path: ./wheelhouse/*.whl + name: release-wheels-${{ matrix.os }} + path: wheelhouse/*.whl pypi-publish: + # This needs to be a separate job because pypa/gh-action-pypi-publish cannot run on macOS # https://github.com/pypa/gh-action-pypi-publish name: Upload wheels to PyPI - needs: build_wheels - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + needs: [build_wheels, make_sdist] runs-on: ubuntu-latest env: CAN_DEPLOY: ${{ secrets.SAGEMATH_PYPI_API_TOKEN != '' }} + permissions: + id-token: write + attestations: write + contents: read steps: - - uses: actions/download-artifact@v4 with: - pattern: wheels-* - path: wheelhouse + pattern: release-* + path: dist + merge-multiple: true + + - name: List files + run: ls -l -R dist + + - name: Generate artifact attestations + uses: actions/attest-build-provenance@v2 + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + with: + subject-path: "dist/*" - name: Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.SAGEMATH_PYPI_API_TOKEN }} - packages-dir: wheelhouse/ - skip_existing: true verbose: true - if: env.CAN_DEPLOY == 'true' + if: env.CAN_DEPLOY == 'true' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags') diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ba4c689f..31a83dd1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,4 +1,4 @@ -name: cypari2 +name: CI on: pull_request: @@ -15,78 +15,112 @@ concurrency: jobs: build: + name: Build and Test (${{ matrix.os }}, Python ${{ matrix.python-version }}, PARI ${{ matrix.pari-version }}) runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest] - python-version: ['3.10', '3.11', '3.12', '3.13'] - pari-version: ['pari-2.13.0', 'pari-2.15.4', 'pari-2.15.5', '2.17.2'] + python-version: ['3.12', '3.13'] + pari-version: ['2.13.0', '2.15.4', '2.15.5', '2.17.2'] + include: + - os: macos-latest + python-version: '3.12' + pari-version: '2.17.2' # Whatever comes with homebrew + - os: macos-latest + python-version: '3.13' + pari-version: '2.17.2' # Whatever comes with homebrew + - os: windows-latest + python-version: '3.12' # Whatever comes with msys2 + pari-version: '2.15.4' + - os: windows-latest + python-version: '3.12' # Whatever comes with msys2 + pari-version: '2.17.2' env: LC_ALL: C PARI_VERSION: ${{ matrix.pari-version }} + defaults: + run: + shell: ${{ matrix.os == 'windows-latest' && 'msys2 {0}' || 'bash' }} steps: - name: Set up the repository uses: actions/checkout@v4 + - name: Setup MSYS2 + if: runner.os == 'Windows' + id: msys2 + uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: >- + base-devel + m4 + bison + make + patch + sed + wget + mingw-w64-ucrt-x86_64-toolchain + mingw-w64-ucrt-x86_64-gmp + mingw-w64-ucrt-x86_64-python + mingw-w64-ucrt-x86_64-python-pip + mingw-w64-ucrt-x86_64-meson-python + mingw-w64-ucrt-x86_64-cython + path-type: inherit - name: Set up Python ${{ matrix.python-version }} + if: runner.os != 'Windows' uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Install pari + - name: Install PARI + if: matrix.os != 'macos-latest' + run: | + bash -x .install-pari.sh + - name: Install PARI + if: matrix.os == 'macos-latest' run: | - bash -x .install-pari.sh - - name: Local build + brew install pari + - name: Smoke test PARI run: | - make install - make check - pip install sphinx - (cd docs && make html) - - dist: - runs-on: ubuntu-latest - steps: - - name: Check out ${{ env.SPKG }} - uses: actions/checkout@v4 - with: - path: build/pkgs/${{ env.SPKG }}/src - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - - name: Install prerequisites - run: | - sudo DEBIAN_FRONTEND=noninteractive apt-get update - sudo DEBIAN_FRONTEND=noninteractive apt-get install $DIST_PREREQ - python3 -m pip install build - - name: Run make dist, prepare upstream artifact - run: | - (cd build/pkgs/${{ env.SPKG }}/src && python3 -m build --sdist) \ - && mkdir -p upstream && cp build/pkgs/${{ env.SPKG }}/src/dist/*.tar.gz upstream/${{ env.SPKG }}-git.tar.gz \ - && echo "sage-package create ${{ env.SPKG }} --version git --tarball ${{ env.SPKG }}-git.tar.gz --type=standard" > upstream/update-pkgs.sh \ - && if [ -n "${{ env.REMOVE_PATCHES }}" ]; then echo "(cd ../build/pkgs/${{ env.SPKG }}/patches && rm -f ${{ env.REMOVE_PATCHES }}; :)" >> upstream/update-pkgs.sh; fi \ - && ls -l upstream/ - - uses: actions/upload-artifact@v4 - with: - path: upstream - name: upstream + if [ ${{ runner.os }} = macOS ]; then + HOMEBREW=`brew --prefix` + clang -v tests/test.c -o test -I$HOMEBREW/include -L$HOMEBREW/lib -lpari -lgmp + else + gcc -v tests/test.c -o test -I/usr/local/include -L/usr/local/bin -lpari -lgmp + fi + expected="zeta(2) = 1.6449340668482264364 + p = x^3 + x^2 + x - 1 + modulus = y^3 + y^2 + y - 1 + centerlift(lift(fq)) = [x - y, 1; x + (y^2 + y - 1), 1; x + (-y^2 - 1), 1]" + output="$(./test)" + # Normalize newlines for comparison + output="$(echo "$output" | tr -d '\r')" + expected="$(echo "$expected" | tr -d '\r')" + echo -e "Got:\n$output" + if [ "$output" != "$expected" ]; then + echo "Unexpected output from test.c" + echo -e "Expected:\n$expected" + exit 1 + fi - sage: - uses: sagemath/sage/.github/workflows/docker.yml@develop - with: - targets: SAGE_CHECK=no SAGE_CHECK_PACKAGES="cypari" cypari - targets_optional: build/make/Makefile - sage_repo: sagemath/sage - sage_ref: develop - upstream_artifact: upstream - # We prefix the image name with the SPKG name ("cypari2-") to avoid the error - # 'Package "sage-docker-..." is already associated with another repository.' - docker_push_repository: ghcr.io/${{ github.repository }}/cypari2- - tox_packages_factors: >- - ["standard"] - needs: [dist] + - name: Setup uv + uses: astral-sh/setup-uv@v6 -env: - # Ubuntu packages to install so that building the sdist can succeed - DIST_PREREQ: libpari-dev pari-doc libbz2-dev bzip2 - # Name of this project in the Sage distribution - SPKG: cypari - # Remove all downstream patches - REMOVE_PATCHES: "*" + - name: Build + run: | + if [ ${{ runner.os }} = Windows ]; then + export C_INCLUDE_PATH=$(cygpath -am "${{ steps.msys2.outputs.msys2-location }}")/usr/local/include + export LIBRARY_PATH=$(cygpath -am "${{ steps.msys2.outputs.msys2-location }}")/usr/local/bin + fi + echo $PATH + echo $C_INCLUDE_PATH + echo $LIBRARY_PATH + uv sync --frozen --inexact -v --no-install-project + uv sync --frozen --inexact -v --no-build-isolation --no-editable --config-settings=builddir=builddir + - name: Test + run: | + uv run make check + - name: Build docs + run: | + uv sync --frozen --inexact -v --group doc + (cd docs && uv run make html) diff --git a/.gitignore b/.gitignore index ccc25a5d..29d4e950 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,3 @@ -# Autogenerated files -# (either by Cython or autogen) -cypari2/auto_gen.pxi.tmp -cypari2/auto_gen.pxi -cypari2/auto_instance.pxi.tmp -cypari2/auto_instance.pxi -cypari2/auto_paridecl.pxd.tmp -cypari2/auto_paridecl.pxd -cypari2/closure.c -cypari2/convert.c -cypari2/custom_block.c -cypari2/gen.c -cypari2/handle_error.c -cypari2/pari_instance.c -cypari2/stack.c -cypari2/string_utils.c - # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/.install-pari.sh b/.install-pari.sh old mode 100644 new mode 100755 index 39b2dde9..ad25f777 --- a/.install-pari.sh +++ b/.install-pari.sh @@ -1,24 +1,177 @@ -# Helper script to install PARI for github workflows +#!/bin/bash + +# Helper script to install PARI (e.g. for CI builds). +# On macOS: the default system fake gcc (clang) is used +# On Linux: the default system gcc is used +# On Windows: uses the ucrt64 toolchain in Msys2 +# On *BSD: should be clang; also make should be gmake # Exit on error set -e -if [ "$URLDIR" = "" ]; then - PURE_VERSION=${PARI_VERSION/pari-} - URLDIR=OLD/${PURE_VERSION%.*} +# Detect platform +PLATFORM="unknown" +case "$(uname -s)" in + MSYS_NT*|MINGW*) + PLATFORM="msys" + ;; + Linux) + PLATFORM="linux" + ;; + Darwin) + PLATFORM="macos" + ;; + FreeBSD) + PLATFORM="freebsd" + ;; + OpenBSD) + PLATFORM="openbsd" + ;; + *) + echo "Unknown platform" + exit 1 + ;; +esac + +# Run the script again in UCRT64 system for msys +if [ "$ucrt" != "0" ] && [ "$PLATFORM" = "msys" ]; then + MSYSTEM=UCRT64 MSYS2_PATH_TYPE=inherit bash --login -c "cd $pwd ; $self" +fi + +# Windows conda prefix is not added to path automatically +# thus mingw compiler is not found later +if [ -n "$CONDA_PREFIX" ]; then + export PATH="$(cygpath "$CONDA_PREFIX")/Library/bin:$PATH" +fi + +if [ "$PARI_VERSION" = "" ]; then + PARI_VERSION=2.17.2 fi +PURE_VERSION=${PARI_VERSION/pari-} +URLDIR=OLD/${PURE_VERSION%.*} + PARI_URL="https://pari.math.u-bordeaux.fr/pub/pari/$URLDIR" PARI_URL1="https://pari.math.u-bordeaux.fr/pub/pari/unix" PARI_URL2="https://pari.math.u-bordeaux.fr/pub/pari/unstable" -# Download PARI sources -wget --no-verbose "$PARI_URL/$PARI_VERSION.tar.gz" -O pari.tgz || wget --no-verbose "$PARI_URL1/pari-$PARI_VERSION.tar.gz" -O pari.tgz || wget --no-verbose "$PARI_URL2/pari-$PARI_VERSION.tar.gz" -O pari.tgz +if [ -d build/pari-$PURE_VERSION ] ; then + echo "Using existing pari-$PURE_VERSION build directory" + cd "build/pari-$PURE_VERSION" +else + echo "Download PARI sources" + if [ ! -d build ] ; then + mkdir build + fi + cd build + + # install wget if not present + if ! command -v wget &> /dev/null + then + if [ "$PLATFORM" = "msys" ]; then + pacman -S --noconfirm mingw-w64-ucrt-x86_64-wget + elif [ "$PLATFORM" = "linux" ]; then + dnf install -y wget + elif [ "$PLATFORM" = "macos" ]; then + brew install wget + fi + fi + + wget --no-verbose "$PARI_URL/$PURE_VERSION.tar.gz" -O "pari-$PURE_VERSION.tgz" \ + || wget --no-verbose "$PARI_URL1/pari-$PURE_VERSION.tar.gz" -O "pari-$PURE_VERSION.tgz" \ + || wget --no-verbose "$PARI_URL2/pari-$PURE_VERSION.tar.gz" -O "pari-$PURE_VERSION.tgz" \ + || wget --no-verbose "$PARI_URL/pari-$PURE_VERSION.tar.gz" -O "pari-$PURE_VERSION.tgz" + tar xzf "pari-$PURE_VERSION.tgz" + cd "pari-$PURE_VERSION" +fi + +# Install gmp if not present +if ! ldconfig -p | grep libgmp >/dev/null 2>&1; then + echo "Installing GMP ..." + if [ "$PLATFORM" = "msys" ]; then + pacman -S --noconfirm mingw-w64-ucrt-x86_64-gmp + MSYSTEM_PREFIX="/ucrt64" + elif [ "$PLATFORM" = "linux" ]; then + if command -v dnf >/dev/null 2>&1; then + dnf install -y gmp-devel + fi + elif [ "$PLATFORM" = "macos" ]; then + brew install gmp + elif [ "$PLATFORM" = "freebsd" ]; then + pkg install -y gmp + elif [ "$PLATFORM" = "openbsd" ]; then + pkg_add gmp + fi +fi -# Install -mkdir Pari42 -tar xzf pari.tgz -C Pari42 -cd Pari42/* -./Configure --prefix=/usr -make gp -sudo make install +echo "Building Pari ..." +if [ "$PLATFORM" = "msys" ]; then + # Remove "export_file='$(LIBPARI).def';" line from config/Makefile.SH" + # Otherwise we get a Segmentation Fault during the resulting dlltool call + sed -i.bak "/export_file='\\\$(LIBPARI).def';/d" config/Makefile.SH +fi +# For debugging: +# export CFLAGS="-g" +if [[ "$PLATFORM" = "msys" ]]; then + # If one installs in a non-default location, then one needs to call os.add_dll_directory + # in Python to find the DLLs. + CONFIG_ARGS="--without-readline --prefix=$MSYSTEM_PREFIX" +else + CONFIG_ARGS="--prefix=/usr" +fi +chmod -R +x ./Configure ./config +./Configure $CONFIG_ARGS + +# On Windows, disable UNIX-specific code in language files +# (not sure why UNIX is defined) +lang_es="src/language/es.c" +if [ -f "$lang_es" ] && [ "$PLATFORM" = "msys" ]; then + sed -i.bak \ + -e 's/#if[[:space:]]*defined(UNIX)/#if 0/' \ + -e 's/#ifdef[[:space:]]*UNIX/#if 0/' \ + "$lang_es" +fi + + +if [ "$PLATFORM" = "msys" ]; then + # Windows + cd Omingw-x86_64 + make install-lib-dyn + make install-include + make install-doc + make install-cfg + + # Fix location of libpari.dll.a + if [ -f "$MSYSTEM_PREFIX/bin/libpari.dll.a" ]; then + cp "$MSYSTEM_PREFIX/bin/libpari.dll.a" "$MSYSTEM_PREFIX/lib/" + fi +else + # Linux or macOS + + # Remove sudo provided by devtoolset since it doesn't work + rm -f /opt/rh/gcc-toolset-14/root/usr/bin/sudo + if ! command -v sudo >/dev/null 2>&1; then + if command -v dnf >/dev/null 2>&1; then + dnf install -y sudo + elif command -v apt-get >/dev/null 2>&1; then + apt-get update + apt-get install -y sudo + elif command -v apk >/dev/null 2>&1; then + apk add sudo + fi + fi + make gp + sudo make install + + # Copy libpari to usr/lib64 (needed on RHEL/CentOS/Fedora) + if [ -d /usr/lib64 ] && [ -f /usr/lib/libpari.so ]; then + sudo cp /usr/lib/libpari.so* /usr/lib64/ + sudo ldconfig + fi + + # Diagnostic output + ls -l /usr/lib | grep libpari || true + ls -L /usr/lib | grep libpari || true + ls -l /usr/local/lib | grep libpari || true + ldconfig -p | grep libpari || true +fi diff --git a/README.rst b/README.rst index 914356fa..1d7e5c36 100644 --- a/README.rst +++ b/README.rst @@ -24,7 +24,7 @@ From a pre-built wheel from PyPI Requirements: -- Python >= 3.9 +- Python >= 3.12 - pip Install cypari2 via the Python Package Index (PyPI) via @@ -42,10 +42,30 @@ From source with pip Requirements: - PARI/GP >= 2.9.4 (header files and library); see +- PARI/GP >= 2.9.4 (header files and library); see https://doc.sagemath.org/html/en/reference/spkg/pari#spkg-pari for availability in distributions (GNU/Linux, conda-forge, Homebrew, FreeBSD), - or install from source. + or install from source (e.g using the script ``.install-pari.sh`` provided in this + repository). +- gmp (if PARI/GP was built with gmp) +- A C compiler (GCC) +- pkg-config +- Python >= 3.12 +- pip + +On Windows, we recommend to use MSYS2, which can be installed from +`Rtools `_. +Afterwards, start the MSYS2 (UCRT64) terminal and install the above +dependencies via +:: + + $ pacman -Syu + $ pacman -S mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-gmp mingw-w64-ucrt-x86_64-python mingw-w64-ucrt-x86_64-python-pip mingw-w64-ucrt-x86_64-meson-python mingw-w64-ucrt-x86_64-cython mingw-w64-ucrt-x86_64-wget mingw-w64-ucrt-x86_64-uv + $ pacman -S bison # for building pari from source + $ .install-pari.sh + $ export C_INCLUDE_PATH=/usr/local/include + $ export LIBRARY_PATH=/usr/local/bin + Install cypari2 via the Python Package Index (PyPI) via @@ -66,6 +86,22 @@ If you want to try the development version, use $ pip install git+https://github.com/sagemath/cypari2.git [--user] +or clone the repository and run +:: + + $ python -m venv venv + $ source venv/bin/activate + $ pip install "meson-python>=0.18.0" "cython>=3.0" "cysignals>=1.11.3" "ninja>=1.8.2" + $ pip install -e . --no-build-isolation + +If you run into certification issues on Windows, you can try to +upgrade the certifi package via +:: + + $ pip install --upgrade certifi + $ export SSL_CERT_FILE=$(python -m certifi) + +and then retry the installation. Usage ----- @@ -143,14 +179,28 @@ CyPari 2 is maintained by the SageMath community. Open issues or submit pull requests at https://github.com/sagemath/cypari2 and join https://groups.google.com/group/sage-devel to discuss. -To get started with development, you can set up an environment using Conda -as follows: +To get started with development, you can use the provided ``environment.yml`` +file to create the full development environment including build backend, +compilers, and documentation dependencies: :: - $ conda create -n cypari2-dev python cython pari=*=*_pthread ninja meson-python cysignals c-compiler + + $ conda env create -f environment.yml $ conda activate cypari2-dev + $ pip install -e . --no-build-isolation -Afterwards, you can build and install the package in editable mode: +On Windows, you can use ``environment-win.yml`` and you may also need to set a +few environment variables: :: + $ conda env create -f environment-win.yml + $ conda activate cypari2-dev + $ set LIBRARY_PATH=%CONDA_PREFIX%\Library\lib;%LIBRARY_PATH% + $ set C_INCLUDE_PATH=%CONDA_PREFIX%\Library\include;%C_INCLUDE_PATH% $ pip install -e . --no-build-isolation + +To update an existing environment after changes to ``environment.yml``: + +:: + + $ conda env update -f environment.yml --prune diff --git a/autogen/__init__.py b/autogen/__init__.py index 21eeb3a1..59dd7c29 100644 --- a/autogen/__init__.py +++ b/autogen/__init__.py @@ -1,26 +1,33 @@ from __future__ import absolute_import -import glob -import os -from os.path import join, getmtime, exists +from pathlib import Path from .generator import PariFunctionGenerator -from .paths import pari_share -def rebuild(force=False): - pari_module_path = 'cypari2' - src_files = [join(pari_share(), 'pari.desc')] + \ - glob.glob(join('autogen', '*.py')) - gen_files = [join(pari_module_path, 'auto_paridecl.pxd'), - join(pari_module_path, 'auto_gen.pxi')] +def rebuild(pari_data: str, force: bool = False, output: None | str = None): + if output is None: + output = "cypari2" + output_dir = Path(output) + # Ensure output directory exists + output_dir.mkdir(parents=True, exist_ok=True) - if not force and all(exists(f) for f in gen_files): - src_mtime = max(getmtime(f) for f in src_files) - gen_mtime = min(getmtime(f) for f in gen_files) + pari_datadir = Path(pari_data) + if not pari_datadir.is_dir(): + raise ValueError(f"PARI data directory {pari_datadir} does not exist or is not a directory") + + src_files = [pari_datadir / "pari.desc"] + list(Path("autogen").glob("*.py")) + gen_files = [ + output_dir / "auto_paridecl.pxd", + output_dir / "auto_gen.pxi", + ] + + if not force and all(f.exists() for f in gen_files): + src_mtime = max(f.stat().st_mtime for f in src_files) + gen_mtime = min(f.stat().st_mtime for f in gen_files) if gen_mtime > src_mtime: return - G = PariFunctionGenerator() + G = PariFunctionGenerator(pari_datadir, output_dir) G() diff --git a/autogen/doc.py b/autogen/doc.py index c71e7c6f..ae1bf5b3 100644 --- a/autogen/doc.py +++ b/autogen/doc.py @@ -4,9 +4,10 @@ """ from __future__ import unicode_literals + import re import subprocess - +import sys leading_ws = re.compile("^( +)", re.MULTILINE) trailing_ws = re.compile("( +)$", re.MULTILINE) @@ -269,6 +270,9 @@ def get_raw_doc(function): ... RuntimeError: no help found for 'abcde' """ + if sys.platform.startswith("win"): + return b"" + doc = subprocess.check_output(["gphelp", "-raw", function]) if doc.endswith(b"""' not found !\n"""): raise RuntimeError("no help found for '{}'".format(function)) diff --git a/autogen/generator.py b/autogen/generator.py index c8f63800..169a878f 100644 --- a/autogen/generator.py +++ b/autogen/generator.py @@ -14,16 +14,15 @@ # **************************************************************************** from __future__ import absolute_import, print_function, unicode_literals -import io + import os import re import sys - +from pathlib import Path from .args import PariArgumentGEN, PariInstanceArgument -from .parser import read_pari_desc, parse_prototype from .doc import get_rest_doc - +from .parser import parse_prototype, read_pari_desc autogen_top = "# This file is auto-generated by {}\n".format( os.path.relpath(__file__)) @@ -83,10 +82,11 @@ class PariFunctionGenerator(object): are written as methods of either :class:`Gen` or :class:`Pari`. """ - def __init__(self): - self.gen_filename = os.path.join('cypari2', 'auto_gen.pxi') - self.instance_filename = os.path.join('cypari2', 'auto_instance.pxi') - self.decl_filename = os.path.join('cypari2', 'auto_paridecl.pxd') + def __init__(self, pari_datadir: Path, output_dir: Path): + self.gen_filename = output_dir / "auto_gen.pxi" + self.instance_filename = output_dir / "auto_instance.pxi" + self.decl_filename = output_dir / "auto_paridecl.pxd" + self.pari_datadir = pari_datadir def can_handle_function(self, function, cname="", **kwds): """ @@ -95,7 +95,8 @@ def can_handle_function(self, function, cname="", **kwds): EXAMPLES:: >>> from autogen.generator import PariFunctionGenerator - >>> G = PariFunctionGenerator() + >>> from pathlib import Path + >>> G = PariFunctionGenerator(Path("test"), Path("dummy")) >>> G.can_handle_function("bnfinit", "bnfinit0", **{"class":"basic"}) True >>> G.can_handle_function("_bnfinit", "bnfinit0", **{"class":"basic"}) @@ -135,7 +136,8 @@ def handle_pari_function(self, function, cname, prototype="", help="", >>> from autogen.parser import read_pari_desc >>> from autogen.generator import PariFunctionGenerator - >>> G = PariFunctionGenerator() + >>> from pathlib import Path + >>> G = PariFunctionGenerator(Path("test"), Path("dummy")) >>> G.gen_file = sys.stdout >>> G.instance_file = sys.stdout >>> G.decl_file = sys.stdout @@ -328,18 +330,19 @@ def __call__(self): """ Top-level function to generate the auto-generated files. """ - D = read_pari_desc() + gen_file_tmp = self.gen_filename.with_suffix('.tmp') + instance_file_tmp = self.instance_filename.with_suffix('.tmp') + decl_file_tmp = self.decl_filename.with_suffix('.tmp') + + D = read_pari_desc(self.pari_datadir) D = sorted(D.values(), key=lambda d: d['function']) sys.stdout.write("Generating PARI functions:") - self.gen_file = io.open(self.gen_filename + '.tmp', - 'w', encoding='utf-8') + self.gen_file = gen_file_tmp.open('w', encoding='utf-8') self.gen_file.write(gen_banner) - self.instance_file = io.open(self.instance_filename + '.tmp', - 'w', encoding='utf-8') + self.instance_file = instance_file_tmp.open('w', encoding='utf-8') self.instance_file.write(instance_banner) - self.decl_file = io.open(self.decl_filename + '.tmp', - 'w', encoding='utf-8') + self.decl_file = decl_file_tmp.open('w', encoding='utf-8') self.decl_file.write(decl_banner) # Check for availability of hi-res SVG plotting. This requires @@ -365,6 +368,6 @@ def __call__(self): self.decl_file.close() # All done? Let's commit. - os.rename(self.gen_filename + '.tmp', self.gen_filename) - os.rename(self.instance_filename + '.tmp', self.instance_filename) - os.rename(self.decl_filename + '.tmp', self.decl_filename) + gen_file_tmp.replace(self.gen_filename) + instance_file_tmp.replace(self.instance_filename) + decl_file_tmp.replace(self.decl_filename) diff --git a/autogen/parser.py b/autogen/parser.py index b0d44cd3..d7127104 100644 --- a/autogen/parser.py +++ b/autogen/parser.py @@ -15,17 +15,16 @@ from __future__ import absolute_import, unicode_literals import io -import os import re +from pathlib import Path from .args import pari_arg_types -from .paths import pari_share from .ret import pari_ret_types paren_re = re.compile(r"[(](.*)[)]") argname_re = re.compile(r"[ {]*&?([A-Za-z_][A-Za-z0-9_]*)") -def read_pari_desc(): +def read_pari_desc(pari_datadir: Path) -> dict[str, dict[str, str]]: """ Read and parse the file ``pari.desc``. @@ -36,7 +35,7 @@ def read_pari_desc(): EXAMPLES:: >>> from autogen.parser import read_pari_desc - >>> D = read_pari_desc() + >>> D = read_pari_desc(Path("tests")) >>> Dcos = D["cos"] >>> if "description" in Dcos: _ = Dcos.pop("description") >>> Dcos.pop("doc").startswith('cosine of $x$.') @@ -49,16 +48,16 @@ def read_pari_desc(): ... 'section': 'transcendental'} True """ - pari_desc = os.path.join(pari_share(), 'pari.desc') + pari_desc = pari_datadir / 'pari.desc' with io.open(pari_desc, encoding="utf-8") as f: lines = f.readlines() n = 0 N = len(lines) - functions = {} + functions: dict[str, dict[str, str]] = {} while n < N: - fun = {} + fun: dict[str, str] = {} while True: L = lines[n]; n += 1 if L == "\n": diff --git a/autogen/paths.py b/autogen/paths.py deleted file mode 100644 index ec98a5b6..00000000 --- a/autogen/paths.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Find out installation paths of PARI/GP -""" - -#***************************************************************************** -# Copyright (C) 2017 Jeroen Demeyer -# -# This 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. -# https://www.gnu.org/licenses/ -#***************************************************************************** - -from __future__ import absolute_import, unicode_literals - -import os -import shutil -from glob import glob - -gppath = shutil.which("gp") - -if gppath is None: - # This almost certainly won't work, but we need to put something here - prefix = "." -else: - # Assume gppath is ${prefix}/bin/gp - prefix = os.path.dirname(os.path.dirname(gppath)) - - -def pari_share(): - r""" - Return the directory where the PARI data files are stored. - - EXAMPLES:: - - >>> import os - >>> from autogen.parser import pari_share - >>> os.path.isfile(os.path.join(pari_share(), "pari.desc")) - True - """ - if "PARI_SHARE" in os.environ: - return os.environ["PARI_SHARE"] - from subprocess import PIPE, Popen - if not gppath: - raise EnvironmentError("cannot find an installation of PARI/GP: make sure that the 'gp' program is in your $PATH") - # Ignore GP_DATA_DIR environment variable - env = dict(os.environ) - env.pop("GP_DATA_DIR", None) - gp = Popen([gppath, "-f", "-q"], stdin=PIPE, stdout=PIPE, env=env) - out = gp.communicate(b"print(default(datadir))")[0] - # Convert out to str if needed - if not isinstance(out, str): - from sys import getfilesystemencoding - out = out.decode(getfilesystemencoding(), "surrogateescape") - datadir = out.strip() - if not os.path.isdir(datadir): - # As a fallback, try a path relative to the prefix - datadir = os.path.join(prefix, "share", "pari") - if not os.path.isdir(datadir): - raise EnvironmentError("PARI data directory {!r} does not exist".format(datadir)) - return datadir - - -def include_dirs(): - """ - Return a list of directories containing PARI include files. - """ - dirs = [os.path.join(prefix, "include")] - return [d for d in dirs if os.path.isdir(os.path.join(d, "pari"))] - - -def library_dirs(): - """ - Return a list of directories containing PARI library files. - """ - dirs = [os.path.join(prefix, s) for s in ("lib", "lib32", "lib64")] - return [d for d in dirs if glob(os.path.join(d, "libpari*"))] diff --git a/cypari2/__init__.py b/cypari2/__init__.py index dbbade7e..a8ff741e 100644 --- a/cypari2/__init__.py +++ b/cypari2/__init__.py @@ -1,6 +1,6 @@ -from .pari_instance import Pari -from .handle_error import PariError -from .gen import Gen -from .custom_block import init_custom_block +from cypari2.custom_block import init_custom_block +from cypari2.gen import Gen +from cypari2.handle_error import PariError +from cypari2.pari_instance import Pari init_custom_block() diff --git a/cypari2/closure.pxd b/cypari2/closure.pxd index 2cabb3ae..21107f39 100644 --- a/cypari2/closure.pxd +++ b/cypari2/closure.pxd @@ -1,3 +1,3 @@ -from .gen cimport Gen +from cypari2.gen cimport Gen cpdef Gen objtoclosure(f) cdef int _pari_init_closure() except -1 diff --git a/cypari2/closure.pyx b/cypari2/closure.pyx index 42c370e3..7ae03931 100644 --- a/cypari2/closure.pyx +++ b/cypari2/closure.pyx @@ -37,9 +37,9 @@ from cpython.tuple cimport * from cpython.object cimport PyObject_Call from cpython.ref cimport Py_INCREF -from .paridecl cimport * -from .stack cimport new_gen, new_gen_noclear, clone_gen_noclear, DetachGen -from .gen cimport objtogen +from cypari2.paridecl cimport * +from cypari2.stack cimport new_gen, new_gen_noclear, clone_gen_noclear, DetachGen +from cypari2.gen cimport objtogen try: from inspect import getfullargspec as getargspec diff --git a/cypari2/convert.pxd b/cypari2/convert.pxd index e6ff2434..36d659d4 100644 --- a/cypari2/convert.pxd +++ b/cypari2/convert.pxd @@ -1,6 +1,6 @@ -from .paridecl cimport (GEN, t_COMPLEX, dbltor, real_0_bit, stoi, cgetg, +from cypari2.paridecl cimport (GEN, t_COMPLEX, dbltor, real_0_bit, stoi, cgetg, set_gel, gen_0) -from .gen cimport Gen +from cypari2.gen cimport Gen from cpython.long cimport PyLong_AsLong from cpython.float cimport PyFloat_AS_DOUBLE from cpython.complex cimport PyComplex_RealAsDouble, PyComplex_ImagAsDouble diff --git a/cypari2/convert.pyx b/cypari2/convert.pyx index 27facc2b..7f10b8bc 100644 --- a/cypari2/convert.pyx +++ b/cypari2/convert.pyx @@ -48,10 +48,10 @@ from cpython.longintrepr cimport (_PyLong_New, from libc.limits cimport LONG_MIN, LONG_MAX from libc.math cimport INFINITY -from .paridecl cimport * -from .stack cimport new_gen, reset_avma -from .string_utils cimport to_string, to_bytes -from .pycore_long cimport (ob_digit, _PyLong_IsZero, _PyLong_IsPositive, +from cypari2.paridecl cimport * +from cypari2.stack cimport new_gen, reset_avma +from cypari2.string_utils cimport to_string, to_bytes +from cypari2.pycore_long cimport (ob_digit, _PyLong_IsZero, _PyLong_IsPositive, _PyLong_DigitCount, _PyLong_SetSignAndDigitCount) ######################################################################## @@ -458,7 +458,7 @@ cdef GEN PyLong_AS_GEN(py_long x) noexcept: # Size of the input cdef size_t sizedigits - cdef long sgn + cdef pari_longword sgn if _PyLong_IsZero(x): return gen_0 elif _PyLong_IsPositive(x): diff --git a/cypari2/custom_block.pyx b/cypari2/custom_block.pyx index 66eeec1a..896659c5 100644 --- a/cypari2/custom_block.pyx +++ b/cypari2/custom_block.pyx @@ -7,9 +7,20 @@ from cysignals.signals cimport add_custom_signals +cdef extern from *: + """ + #include "pari_compat.h" + """ + cdef extern from "pari/pari.h": int PARI_SIGINT_block, PARI_SIGINT_pending +cdef extern from *: + """ + // see pari_long.pxd for explanation + #undef long // custom_block + """ + cdef int custom_signal_is_blocked() noexcept: return PARI_SIGINT_block diff --git a/cypari2/cypari2.py.in b/cypari2/cypari2.py.in new file mode 100644 index 00000000..59a19aca --- /dev/null +++ b/cypari2/cypari2.py.in @@ -0,0 +1,6 @@ +includedir=${pcfiledir} + +Name: cypari2 +Description: cypari2 library +Version: @version@ +Cflags: -I${includedir} diff --git a/cypari2/gen.pxd b/cypari2/gen.pxd index 9579dee6..9dcef059 100644 --- a/cypari2/gen.pxd +++ b/cypari2/gen.pxd @@ -1,6 +1,6 @@ cimport cython from cpython.object cimport PyObject -from .types cimport GEN, pari_sp +from cypari2.types cimport GEN, pari_sp cdef class Gen_base: diff --git a/cypari2/gen.pyx b/cypari2/gen.pyx index b016ce3d..07ce3732 100644 --- a/cypari2/gen.pyx +++ b/cypari2/gen.pyx @@ -62,17 +62,17 @@ from cpython.object cimport (Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, PyTypeObject) from cysignals.memory cimport sig_free, check_malloc from cysignals.signals cimport sig_check, sig_on, sig_off, sig_block, sig_unblock -from .types cimport * -from .string_utils cimport to_string, to_bytes -from .paripriv cimport * -from .convert cimport PyObject_AsGEN, gen_to_integer -from .pari_instance cimport DEFAULT_BITPREC, get_var -from .stack cimport (new_gen, new_gens2, new_gen_noclear, +from cypari2.types cimport * +from cypari2.string_utils cimport to_string, to_bytes +from cypari2.paripriv cimport * +from cypari2.convert cimport PyObject_AsGEN, gen_to_integer +from cypari2.pari_instance cimport DEFAULT_BITPREC, get_var +from cypari2.stack cimport (new_gen, new_gens2, new_gen_noclear, clone_gen, clear_stack, reset_avma, remove_from_pari_stack, move_gens_to_heap) -from .closure cimport objtoclosure +from cypari2.closure cimport objtoclosure -from .paridecl cimport * +from cypari2.paridecl cimport * include 'auto_gen.pxi' @@ -857,8 +857,8 @@ cdef class Gen(Gen_base): >>> pari.polcyclo(15).nfinit().nf_get_sign() [0, 4] """ - cdef long r1 - cdef long r2 + cdef pari_longword r1 + cdef pari_longword r2 cdef GEN sign sig_on() sign = member_sign(self.g) @@ -1115,7 +1115,7 @@ cdef class Gen(Gen_base): >>> K.idealprimedec(5)[0].pr_get_e() 1 """ - cdef long e + cdef pari_longword e sig_on() e = pr_get_e(self.g) sig_off() @@ -1717,7 +1717,7 @@ cdef class Gen(Gen_base): """ cdef GEN x cdef long lx - cdef long *xp + cdef GEN xp cdef long w cdef char *s cdef char *sp @@ -1760,27 +1760,27 @@ cdef class Gen(Gen_base): """ cdef GEN x cdef long lx - cdef long *xp + cdef GEN xp cdef long w cdef char *s cdef char *sp cdef char *hexdigits = "0123456789abcdef" cdef int i, j - cdef int size + cdef pari_longword size x = self.g if typ(x) != t_INT: raise TypeError("gen must be of PARI type t_INT") if not signe(x): return "0x0" lx = lgefint(x) - 2 # number of words - size = lx*2*sizeof(long) + size = lx*2*sizeof(pari_ulongword) s = check_malloc(size+4) # 1 char for sign, 2 chars for 0x, 1 char for '\0' sp = s + size + 4 - 1 # last character sp[0] = 0 xp = int_LSW(x) for i from 0 <= i < lx: w = xp[0] - for j in range(2*sizeof(long)): + for j in range(2*sizeof(pari_longword)): sp -= 1 sp[0] = hexdigits[w & 15] w >>= 4 @@ -1948,7 +1948,7 @@ cdef class Gen(Gen_base): >>> pari('389/17').python() Fraction(389, 17) """ - from .convert import gen_to_python + from cypari2.convert import gen_to_python return gen_to_python(self) def sage(self, locals=None): @@ -2215,7 +2215,7 @@ cdef class Gen(Gen_base): False """ sig_on() - cdef long t = ispseudoprime(self.g, flag) + cdef pari_longword t = ispseudoprime(self.g, flag) sig_off() return t != 0 @@ -2702,7 +2702,7 @@ cdef class Gen(Gen_base): >>> pari('(2.4*x^2 - 1.7)/x').truncate() 2.40000000000000*x """ - cdef long e + cdef pari_longword e cdef Gen y sig_on() if not estimate: @@ -2830,7 +2830,7 @@ cdef class Gen(Gen_base): >>> pari('sin(x+O(x^10))').round() # each coefficient has abs < 1 x + O(x^10) """ - cdef long e + cdef pari_longword e cdef Gen y sig_on() if not estimate: @@ -3113,7 +3113,7 @@ cdef class Gen(Gen_base): ``find_root`` is given, also returns the exact square root. """ cdef GEN G - cdef long t + cdef pari_longword t sig_on() if find_root: t = itos(gissquareall(x.g, &G)) @@ -4065,7 +4065,7 @@ cdef class Gen(Gen_base): cdef long t = typ(self.g) cdef Gen t0 cdef GEN result - cdef long arity + cdef pari_longword arity cdef long nargs = len(args) cdef long nkwds = len(kwds) diff --git a/cypari2/handle_error.pxd b/cypari2/handle_error.pxd index ef5e9182..b6a7d885 100644 --- a/cypari2/handle_error.pxd +++ b/cypari2/handle_error.pxd @@ -1,5 +1,6 @@ -from .types cimport GEN +from cypari2.pari_long cimport pari_longword, pari_ulongword +from cypari2.types cimport GEN cdef void _pari_init_error_handling() noexcept cdef int _pari_err_handle(GEN E) except 0 -cdef void _pari_err_recover(long errnum) noexcept +cdef void _pari_err_recover(pari_longword errnum) noexcept diff --git a/cypari2/handle_error.pyx b/cypari2/handle_error.pyx index 5789ee24..b2f8660f 100644 --- a/cypari2/handle_error.pyx +++ b/cypari2/handle_error.pyx @@ -25,9 +25,8 @@ from cpython cimport PyErr_Occurred from cysignals.signals cimport sig_block, sig_unblock, sig_error -from .paridecl cimport * -from .paripriv cimport * -from .stack cimport clone_gen_noclear, reset_avma, after_resize +from cypari2.paridecl cimport cb_pari_err_recover, cb_pari_err_handle, e_STACK, pari_mainstack, pari_err2str, pari_free, closure_func_err +from cypari2.stack cimport clone_gen_noclear, reset_avma, after_resize # We derive PariError from RuntimeError, for backward compatibility with @@ -211,7 +210,7 @@ cdef int _pari_err_handle(GEN E) except 0: raise PariError(errnum, pari_error_string, clone_gen_noclear(E)) -cdef void _pari_err_recover(long errnum) noexcept: +cdef void _pari_err_recover(pari_longword errnum) noexcept: """ Reset the error string and jump back to ``sig_on()``, either to retry the code (in case of no error) or to make the already-raised diff --git a/cypari2/meson.build b/cypari2/meson.build index 3475f26a..4c375535 100644 --- a/cypari2/meson.build +++ b/cypari2/meson.build @@ -13,9 +13,6 @@ py.install_sources( 'types.pxd', 'cypari.h', 'pycore_long.h', - 'auto_paridecl.pxd', - 'auto_gen.pxi', - 'auto_instance.pxi', subdir: 'cypari2' ) @@ -31,6 +28,13 @@ extension_data = { 'pari_instance': files('pari_instance.pyx') } +inc_src = include_directories('.') +# Meson currently ignores include_directories for Cython modules, so we +# have to add them manually. +# https://github.com/mesonbuild/meson/issues/9562 +add_project_arguments('-I', meson.current_source_dir(), language: 'cython') +add_project_arguments('-I', meson.current_build_dir(), language: 'cython') + foreach name, pyx : extension_data py.extension_module( name, @@ -38,6 +42,16 @@ foreach name, pyx : extension_data subdir: 'cypari2', install: true, dependencies: [cysignals, pari], + include_directories: [inc_root, inc_src], ) endforeach +config_data = configuration_data() +config_data.set('version', meson.project_version()) +configure_file( + input: 'cypari2.py.in', + output: 'cypari2.py', + configuration: config_data, + install: true, + install_dir: py.get_install_dir() / 'cypari2' +) diff --git a/cypari2/pari_compat.h b/cypari2/pari_compat.h new file mode 100644 index 00000000..a350b3b5 --- /dev/null +++ b/cypari2/pari_compat.h @@ -0,0 +1,31 @@ +#ifdef _MSC_VER +// The following should probably work to get inline working on Windows +// with MSVC, but it doesn't. So we just disable inlining for now. +//# define inline __inline +//# define INLINE static inline +# define DISABLE_INLINE 1 + +// Pari doesn't annotate those exports with __declspec(dllimport), so we +// need to use linker directives to avoid "unresolved external symbol" errors. +#pragma comment(linker, "/alternatename:win32ctrlc=__imp_win32ctrlc") +#pragma comment(linker, "/alternatename:PARI_SIGINT_block=__imp_PARI_SIGINT_block") +#pragma comment(linker, "/alternatename:PARI_SIGINT_pending=__imp_PARI_SIGINT_pending") +#pragma comment(linker, "/alternatename:pari_mainstack=__imp_pari_mainstack") +#pragma comment(linker, "/alternatename:avma=__imp_avma") +#pragma comment(linker, "/alternatename:gen_0=__imp_gen_0") +#pragma comment(linker, "/alternatename:cb_pari_err_handler=__imp_cb_pari_err_handler") +#pragma comment(linker, "/alternatename:cb_pari_err_recover=__imp_cb_pari_err_recover") +#pragma comment(linker, "/alternatename:GP_DATA=__imp_GP_DATA") +#pragma comment(linker, "/alternatename:pariOut=__imp_pariOut") +#pragma comment(linker, "/alternatename:LOG10_2=__imp_LOG10_2") +#pragma comment(linker, "/alternatename:new_galois_format=__imp_new_galois_format") +#pragma comment(linker, "/alternatename:factor_proven=__imp_factor_proven") +#pragma comment(linker, "/alternatename:precdl=__imp_precdl") +#pragma comment(linker, "/alternatename:gen_1=__imp_gen_1") +#pragma comment(linker, "/alternatename:gen_2=__imp_gen_2") +#pragma comment(linker, "/alternatename:gnil=__imp_gnil") +#pragma comment(linker, "/alternatename:ghalf=__imp_ghalf") +#pragma comment(linker, "/alternatename:err_e_STACK=__imp_err_e_STACK") +#pragma comment(linker, "/alternatename:cb_pari_err_handle=__imp_cb_pari_err_handle") + +#endif // _MSC_VER diff --git a/cypari2/pari_instance.pxd b/cypari2/pari_instance.pxd index d6a75a7f..19ffd112 100644 --- a/cypari2/pari_instance.pxd +++ b/cypari2/pari_instance.pxd @@ -1,7 +1,7 @@ -from .types cimport * +from cypari2.types cimport * cimport cython -from .gen cimport Gen +from cypari2.gen cimport Gen # DEPRECATED INTERNAL FUNCTION used (incorrectly) in sagemath < 10.5 cpdef long prec_words_to_bits(long prec_in_words) noexcept diff --git a/cypari2/pari_instance.pyx b/cypari2/pari_instance.pyx index a0e89df0..3eb3256c 100644 --- a/cypari2/pari_instance.pyx +++ b/cypari2/pari_instance.pyx @@ -290,14 +290,14 @@ cimport cython from cysignals.signals cimport sig_check, sig_on, sig_off, sig_error -from .string_utils cimport to_string, to_bytes -from .paridecl cimport * -from .paripriv cimport * -from .gen cimport Gen, objtogen -from .stack cimport (new_gen, new_gen_noclear, clear_stack, +from cypari2.string_utils cimport to_string, to_bytes +from cypari2.paridecl cimport * +from cypari2.paripriv cimport GP_DATA, gpd_TEST +from cypari2.gen cimport Gen, objtogen +from cypari2.stack cimport (new_gen, new_gen_noclear, clear_stack, set_pari_stack_size, before_resize, after_resize) -from .handle_error cimport _pari_init_error_handling -from .closure cimport _pari_init_closure +from cypari2.handle_error cimport _pari_init_error_handling +from cypari2.closure cimport _pari_init_closure ################################################################# diff --git a/cypari2/pari_long.pxd b/cypari2/pari_long.pxd new file mode 100644 index 00000000..3f932762 --- /dev/null +++ b/cypari2/pari_long.pxd @@ -0,0 +1,14 @@ +# On 64-bit Windows, the PARI library’s header file parigen.h includes the +# following preprocessor definition: +# #define long long long +# Since the long type in Windows compilers remains 32 bits wide +# (unlike on many Unix-like systems where it is 64 bits), this macro substitution +# creates problems. We work around this by defining our own types +# pari_longword and pari_ulongword, which are guaranteed to be 64 bits wide. + +IF UNAME_SYSNAME == "Windows": + ctypedef long long pari_longword + ctypedef unsigned long long pari_ulongword +ELSE: + ctypedef long pari_longword + ctypedef unsigned long pari_ulongword diff --git a/cypari2/paridecl.pxd b/cypari2/paridecl.pxd index 8bd243b1..e3aa8b0d 100644 --- a/cypari2/paridecl.pxd +++ b/cypari2/paridecl.pxd @@ -32,7 +32,9 @@ from __future__ import print_function from libc.stdio cimport FILE from cpython.getargs cimport va_list -from .types cimport * +from cypari2.pari_long cimport pari_longword, pari_ulongword + +from cypari2.types cimport * cdef extern from *: # PARI headers already included by types.pxd @@ -92,7 +94,7 @@ cdef extern from *: # PARI headers already included by types.pxd # _pari_err_handle() in handle_error.pyx int (*cb_pari_err_handle)(GEN) except 0 int (*cb_pari_handle_exception)(long) except 0 - void (*cb_pari_err_recover)(long) + void (*cb_pari_err_recover)(pari_longword) # kernel/gmp/int.h @@ -2920,6 +2922,7 @@ cdef extern from *: # PARI headers already included by types.pxd GEN closure_evalnobrk(GEN C) GEN closure_evalres(GEN C) void closure_evalvoid(GEN C) + const char * closure_func_err() GEN closure_trapgen(GEN C, long numerr) GEN copybin_unlink(GEN C) GEN get_lex(long vn) @@ -3204,7 +3207,7 @@ cdef extern from *: # PARI headers already included by types.pxd GEN divrem(GEN x, GEN y, long v) GEN floor_safe(GEN x) GEN gceil(GEN x) - GEN gcvtoi(GEN x, long *e) + GEN gcvtoi(GEN x, pari_longword *e) GEN gdeflate(GEN x, long v, long d) GEN gdivent(GEN x, GEN y) GEN gdiventgs(GEN x, long y) @@ -3239,7 +3242,7 @@ cdef extern from *: # PARI headers already included by types.pxd long gprecision(GEN x) GEN gpserprec(GEN x, long v) GEN greal(GEN x) - GEN grndtoi(GEN x, long *e) + GEN grndtoi(GEN x, pari_longword *e) GEN ground(GEN x) GEN gshift(GEN x, long n) GEN gsubst(GEN x, long v, GEN y) @@ -4152,7 +4155,7 @@ cdef extern from *: # PARI headers already included by types.pxd GEN gprimepi_upper_bound(GEN x) GEN gprimepi_lower_bound(GEN x) long isprime(GEN x) - long ispseudoprime(GEN x, long flag) + pari_longword ispseudoprime(GEN x, long flag) long millerrabin(GEN n, long k) GEN prime(long n) GEN primepi(GEN x) @@ -4566,7 +4569,7 @@ cdef extern from *: # PARI headers already included by types.pxd GEN icopy_avma(GEN x, pari_sp av) ulong int_bit(GEN x, long n) GEN itor(GEN x, long prec) - long itos(GEN x) + pari_longword itos(GEN x) long itos_or_0(GEN x) ulong itou(GEN x) ulong itou_or_0(GEN x) @@ -4813,8 +4816,8 @@ cdef extern from *: # PARI headers already included by types.pxd GEN nf_get_zk(GEN nf) GEN nf_get_zkden(GEN nf) GEN nf_get_zkprimpart(GEN nf) - long pr_get_e(GEN pr) - long pr_get_f(GEN pr) + pari_longword pr_get_e(GEN pr) + pari_longword pr_get_f(GEN pr) GEN pr_get_gen(GEN pr) GEN pr_get_p(GEN pr) GEN pr_get_tau(GEN pr) @@ -4845,7 +4848,7 @@ cdef extern from *: # PARI headers already included by types.pxd GEN znstar_get_pe(GEN G) GEN znstar_get_Ui(GEN G) - long closure_arity(GEN C) + pari_longword closure_arity(GEN C) const char * closure_codestr(GEN C) GEN closure_get_code(GEN C) GEN closure_get_oper(GEN C) @@ -5336,7 +5339,7 @@ cdef inline int is_universal_constant(GEN x) noexcept: # Auto-generated declarations. There are taken from the PARI version # on the system, so they more up-to-date than the above. In case of # conflicting declarations, auto_paridecl should have priority. -from .auto_paridecl cimport * +from cypari2.auto_paridecl cimport * cdef inline int is_on_stack(GEN x) except -1: diff --git a/cypari2/paripriv.pxd b/cypari2/paripriv.pxd index dbe13d74..1c50eb50 100644 --- a/cypari2/paripriv.pxd +++ b/cypari2/paripriv.pxd @@ -4,7 +4,7 @@ Declarations for private functions from PARI Ideally, we shouldn't use these, but for technical reasons, we have to. """ -from .types cimport * +from cypari2.types cimport * cdef extern from "pari/paripriv.h": int t_FF_FpXQ, t_FF_Flxq, t_FF_F2xq diff --git a/cypari2/stack.pxd b/cypari2/stack.pxd index 1540d9b5..2bb10512 100644 --- a/cypari2/stack.pxd +++ b/cypari2/stack.pxd @@ -1,6 +1,11 @@ -from .types cimport GEN, pari_sp -from .gen cimport Gen_base, Gen - +from cypari2.types cimport GEN, pari_sp +from cypari2.gen cimport Gen_base, Gen + +cdef extern from *: + """ + // see pari_long.pxd for explanation + #undef long // stack + """ cdef Gen new_gen(GEN x) cdef new_gens2(GEN x, GEN y) diff --git a/cypari2/stack.pyx b/cypari2/stack.pyx index 11a10252..eac2ebf8 100644 --- a/cypari2/stack.pyx +++ b/cypari2/stack.pyx @@ -22,8 +22,9 @@ from cpython.exc cimport PyErr_SetString from cysignals.signals cimport (sig_on, sig_off, sig_block, sig_unblock, sig_error) -from .gen cimport Gen, Gen_new -from .paridecl cimport (avma, pari_mainstack, gnil, gcopy, +from cypari2.paridecl cimport gnil +from cypari2.gen cimport Gen, Gen_new +from cypari2.paridecl cimport (avma, pari_mainstack, gnil, gcopy, is_universal_constant, is_on_stack, isclone, gclone, gclone_refc, paristack_setsize) diff --git a/cypari2/types.pxd b/cypari2/types.pxd index 2c6487dc..78e41eae 100644 --- a/cypari2/types.pxd +++ b/cypari2/types.pxd @@ -18,6 +18,13 @@ from PARI's include files. # https://www.gnu.org/licenses/ # **************************************************************************** +cdef extern from *: + """ + #include "pari_compat.h" + """ + +from cypari2.pari_long cimport pari_longword, pari_ulongword + cdef extern from "pari/pari.h": ctypedef unsigned long ulong "pari_ulong" @@ -82,7 +89,7 @@ cdef extern from "pari/pari.h": long evaltyp(long x) long evallg(long x) long evalvarn(long x) - long evalsigne(long x) + pari_longword evalsigne(long x) long evalprecp(long x) long evalvalp(long x) long evalexpo(long x) diff --git a/environment-win.yml b/environment-win.yml new file mode 100644 index 00000000..e2c87020 --- /dev/null +++ b/environment-win.yml @@ -0,0 +1,24 @@ +# Conda environment for cypari2 development on Windows +# (using mingw-w64 toolchain) +# +# Usage: +# mamba/conda env create -f environment-win.yml +# conda activate cypari2-dev +# pip install -e . --no-build-isolation +name: cypari2-dev +channels: + - conda-forge + +dependencies: + # Build backend and build tools + - python>=3.12 + - pari + - cython>=3.0 + - cysignals>=1.11.3 + - meson-python>=0.18 + - gcc_win-64 + - m2w64-sysroot_win-64 + - m2-base # For running .install-pari.sh + - m2-make # For running .install-pari.sh + # For docs + - sphinx diff --git a/environment.yml b/environment.yml new file mode 100644 index 00000000..82fc6cad --- /dev/null +++ b/environment.yml @@ -0,0 +1,20 @@ +# Conda environment for cypari2 development +# +# Usage: +# mamba/conda env create -f environment.yml +# conda activate cypari2-dev +# pip install -e . --no-build-isolation +name: cypari2-dev +channels: + - conda-forge + +dependencies: + # Build backend and build tools + - python>=3.12 + - pari + - cython>=3.0 + - cysignals>=1.11.3 + - meson-python>=0.18 + - compilers + # For docs + - sphinx diff --git a/meson.build b/meson.build index 0b9eb67f..f0028779 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project('cypari2', version: files('VERSION'), license: 'GPL v2+', default_options: ['c_std=c17', 'python.install_env=auto'], - meson_version: '>=1.2', + meson_version: '>=1.5.0', ) # Python module @@ -15,6 +15,8 @@ cc = meson.get_compiler('c') cython = meson.get_compiler('cython') # Workaround as described in https://cython.readthedocs.io/en/latest/src/userguide/special_methods.html#arithmetic-methods add_project_arguments('-X c_api_binop_methods=True', language: 'cython') +# Compiler debug output +run_command(cc, '-v', check:true) # Dependencies inc_cysignals = run_command( @@ -34,8 +36,90 @@ except Exception: check: true, ).stdout().strip() cysignals = declare_dependency(include_directories: inc_cysignals) + +# Find PARI +# GMP may be a dependency of Pari, but since Pari doesn't have a pkg-config file, +# we have to find it ourselves. +gmp = dependency('gmp', required: false) # Cannot be found via pkg-config -pari = cc.find_library('pari', required: true) +# Also require shared library, since otherwise every Cython extension would include it's own copy of pari leading to hard-to-debug segmentation faults at runtime +pari_header_include_dirs = [] # additional dirs to search for PARI headers +pari_lib_dirs = [] # additional dirs to search for the PARI library +if host_machine.system() == 'darwin' + brew = find_program('brew', required: false) + if brew.found() + brew_prefix = run_command(brew, '--prefix', check: true).stdout().strip() + message('Homebrew prefix: ' + brew_prefix) + pari_header_include_dirs += include_directories(brew_prefix + '/include') + pari_lib_dirs += [brew_prefix + '/lib'] + endif +endif + +# Explicitly check for header to give better error message (using -v to show search paths) +cc.has_header( + 'pari/pari.h', + required: true, + args: ['-v'], + include_directories: pari_header_include_dirs, +) +pari = cc.find_library( + 'pari', + has_headers: ['pari/pari.h'], + required: true, + dirs: pari_lib_dirs, + header_include_directories: pari_header_include_dirs, +) +pari = declare_dependency(include_directories: pari_header_include_dirs, + dependencies: [pari, gmp]) + +# Get PARI version (mostly as smoke test) +pari_version_code = ''' +#include +#include +int main(void) { + pari_init(1000000, 2); + GEN v = pari_version(); + const char *version = GENtostr(pari_version()); + pari_printf("%s",version); + pari_close(); + return 0; +} +''' +pari_version = cc.run( + pari_version_code, + args: ['-v'], + name: 'pari version', + dependencies: [pari], + required: true, +) +message('PARI Version: ' + pari_version.stdout()) + +pari_datadir_code = ''' +#include +#include +int main(void) { + pari_init(1000000, 2); + pari_printf("%s", pari_datadir); + pari_close(); + return 0; +} +''' +pari_datadir = cc.run( + pari_datadir_code, + name: 'pari datadir', + dependencies: [pari], + required: true, +).stdout() + +# In MSYS, convert to Windows path +# (e.g /usr/share/pari -> C:\msys64\usr\share\pari) +if host_machine.system() == 'windows' + pari_datadir = run_command( + 'cygpath', '-am', pari_datadir, + check: true, + ).stdout().strip() +endif +message('PARI Datadir: ' + pari_datadir) # Run code generation step code_gen_result = run_command( @@ -44,10 +128,24 @@ code_gen_result = run_command( import sys sys.path.insert(0, ".") from autogen import rebuild -rebuild(force=True) +rebuild(r"''' + pari_datadir + '''", force=True, output=r"''' + meson.current_build_dir() + '''/cypari2") print("Code generation successful") ''', check: true ) +py.install_sources( + meson.current_build_dir() + '/cypari2/auto_paridecl.pxd', + meson.current_build_dir() + '/cypari2/auto_gen.pxi', + meson.current_build_dir() + '/cypari2/auto_instance.pxi', + subdir: 'cypari2' +) +inc_root = include_directories('.') +# Meson currently ignores include_directories for Cython modules, so we +# have to add them manually. +# https://github.com/mesonbuild/meson/issues/9562 +add_project_arguments('-I', meson.current_source_dir(), language: 'cython') +add_project_arguments('-I', meson.current_build_dir(), language: 'cython') + subdir('cypari2') +subdir('tests') diff --git a/pyproject.toml b/pyproject.toml index 48a3d5d9..4625209e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,12 +12,43 @@ maintainers = [ { name = "SageMath developers", email = "sage-devel@googlegroups.com" }, ] dependencies = ["cysignals>=1.11.3"] -requires-python = ">=3.9" +requires-python = ">=3.12" readme = "README.rst" license = "GPL-2.0-or-later" license-files = ["LICENSE"] keywords = ["PARI/GP number theory"] dynamic = ["version"] +[project.entry-points.pkg_config] +cysignals = 'cysignals' + [project.urls] Homepage = "https://github.com/sagemath/cypari2" + +[dependency-groups] +dev = [ + "build>=1.3.0", + "cibuildwheel>=2.23.3", + "cython>=3.1.4", + "meson>=1.9.0", + "meson-python>=0.18.0", + "ninja>=1.13.0", + "pkgconf>=2.4.3.post2", + "pytest>=8.4.2", +] +doc = [ + "sphinx", +] + +[tool.cibuildwheel] +skip = ["*-win32"] +test-groups = ["dev"] +test-sources = ["tests", "pyproject.toml"] +test-command = "python tests/rundoctest.py" +build-frontend = "build[uv]" +build-verbosity = 1 +before-all = "bash -x {package}/.install-pari.sh" +environment-pass = ["CI", "GITHUB_ACTIONS"] + +[tool.cibuildwheel.macos] +before-all = "brew install pari" diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 00000000..32c088af --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,15 @@ +extension_data = { + 'test': files('test.pyx'), +} + +foreach name, pyx : extension_data + py.extension_module( + name, + sources: pyx, + subdir: 'cypari2', + install: true, + dependencies: [cysignals, pari], + include_directories: [inc_root, include_directories('./../cypari2')], + ) +endforeach + diff --git a/tests/pari.desc b/tests/pari.desc new file mode 100644 index 00000000..a57c75cd --- /dev/null +++ b/tests/pari.desc @@ -0,0 +1,46992 @@ +Function: !_ +Class: basic +Section: symbolic_operators +C-Name: gnot +Prototype: G +Help: !a: boolean operator "not". +Description: + (negbool):bool:parens $1 + (bool):negbool:parens $1 + +Function: #_ +Class: basic +Section: symbolic_operators +C-Name: glength +Prototype: lG +Help: #x: number of non code words in x, number of characters for a string. +Description: + (vecsmall):lg lg($1) + (vec):lg lg($1) + (pol):small lgpol($1) + (gen):small glength($1) + +Function: #_~ +Class: basic +Section: symbolic_operators +C-Name: gtranslength +Prototype: lG +Help: #x~: number of non code words in x~ +Description: + (gen):small gtranslength($1) + +Function: % +Class: basic +Section: symbolic_operators +C-Name: pari_get_hist +Prototype: D0,L, +Help: last history item. + +Function: %# +Class: basic +Section: symbolic_operators +C-Name: pari_histtime +Prototype: D0,L, +Help: time to compute last history item. + +Function: +_ +Class: basic +Section: symbolic_operators +Help: +_: copy and return its argument +Description: + (small):small:parens $1 + (int):int:parens:copy $1 + (real):real:parens:copy $1 + (mp):mp:parens:copy $1 + (gen):gen:parens:copy $1 + +Function: -_ +Class: basic +Section: symbolic_operators +C-Name: gneg +Prototype: G +Help: -_: negate argument +Description: + (small):small:parens -$(1) + (int):int negi($1) + (real):real negr($1) + (mp):mp mpneg($1) + (gen):gen gneg($1) + + (Fp):Fp Fp_neg($1, p) + (FpX):FpX FpX_neg($1, p) + (Fq):Fq Fq_neg($1, T, p) + (FqX):FqX FqX_neg($1, T, p) + +Function: Catalan +Class: basic +Section: transcendental +C-Name: mpcatalan +Prototype: p +Help: Catalan=Catalan(): Catalan's number with current precision. +Description: + ():real:prec mpcatalan($prec) +Doc: Catalan's constant $G = \sum_{n>=0}\dfrac{(-1)^{n}}{(2n+1)^{2}} + =0.91596\cdots$. + Note that \kbd{Catalan} is one of the few reserved names which cannot be + used for user variables. + +Function: Col +Class: basic +Section: conversions +C-Name: gtocol0 +Prototype: GD0,L, +Help: Col(x,{n}): transforms the object x into a column vector of dimension n. +Description: + (gen):vec gtocol($1) +Doc: + transforms the object $x$ into a column vector. The dimension of the + resulting vector can be optionally specified via the extra parameter $n$. + + If $n$ is omitted or $0$, the dimension depends on the type of $x$; the + vector has a single component, except when $x$ is + + \item a vector or a quadratic form (in which case the resulting vector + is simply the initial object considered as a row vector), + + \item a polynomial or a power series. In the case of a polynomial, the + coefficients of the vector start with the leading coefficient of the + polynomial, while for power series only the significant coefficients are + taken into account, but this time by increasing order of degree. + In this last case, \kbd{Vec} is the reciprocal function of \kbd{Pol} and + \kbd{Ser} respectively, + + \item a matrix (the column of row vector comprising the matrix is returned), + + \item a character string (a vector of individual characters is returned). + + In the last two cases (matrix and character string), $n$ is meaningless and + must be omitted or an error is raised. Otherwise, if $n$ is given, $0$ + entries are appended at the end of the vector if $n > 0$, and prepended at + the beginning if $n < 0$. The dimension of the resulting vector is $|n|$. + + See ??Vec for examples and further details. +Variant: \fun{GEN}{gtocol}{GEN x} is also available. + +Function: Colrev +Class: basic +Section: conversions +C-Name: gtocolrev0 +Prototype: GD0,L, +Help: Colrev(x,{n}): transforms the object x into a column vector of + dimension n in reverse order with respect to Col(x,{n}). Empty vector if x + is omitted. +Description: + (gen):vec gtocolrev($1) +Doc: + as $\kbd{Col}(x, -n)$, then reverse the result. In particular, + \kbd{Colrev} is the reciprocal function of \kbd{Polrev}: the + coefficients of the vector start with the constant coefficient of the + polynomial and the others follow by increasing degree. +Variant: \fun{GEN}{gtocolrev}{GEN x} is also available. + +Function: DEBUGLEVEL +Class: gp2c +C-Name: DEBUGLEVEL +Prototype: v +Description: + ():small DEBUGLEVEL + +Function: Euler +Class: basic +Section: transcendental +C-Name: mpeuler +Prototype: p +Help: Euler=Euler(): Euler's constant with current precision. +Description: + ():real:prec mpeuler($prec) +Doc: Euler's constant $\gamma=0.57721\cdots$. Note that + \kbd{Euler} is one of the few reserved names which cannot be used for + user variables. + +Function: I +Class: basic +Section: transcendental +C-Name: gen_I +Prototype: +Help: I=I(): square root of -1. +Description: +Doc: the complex number $\sqrt{-1}$. + +Function: List +Class: basic +Section: conversions +C-Name: gtolist +Prototype: DG +Help: List({x=[]}): transforms the vector or list x into a list. Empty list + if x is omitted. +Description: + ():list mklist() + (gen):list listinit(gtolist($1)) +Doc: + transforms a (row or column) vector $x$ into a list, whose components are + the entries of $x$. Similarly for a list, but rather useless in this case. + For other types, creates a list with the single element $x$. +Variant: The variant \fun{GEN}{mklist}{void} creates an empty list. + +Function: Map +Class: basic +Section: conversions +C-Name: gtomap +Prototype: DG +Help: Map({x}): converts the matrix [a_1,b_1;a_2,b_2;...;a_n,b_n] to the map a_i->b_i. +Description: + ():list mkmap() + (gen):list listinit(gtomap($1)) +Doc: A ``Map'' is an associative array, or dictionary: a data + type composed of a collection of (\emph{key}, \emph{value}) pairs, such that + each key appears just once in the collection. This function + converts the matrix $[a_{1},b_{1};a_{2},b_{2};\dots;a_{n},b_{n}]$ + to the map $a_{i}\mapsto b_{i}$. + \bprog + ? M = Map(factor(13!)); + ? mapget(M, 3) + %2 = 5 + ? P = Map(matreduce(primes([1,20]))) + %3 = Map([2,1;3,1;5,1;7,1;11,1;13,1;17,1;19,1]) + ? select(i->mapisdefined(P,i), [1..20]) + %4 = [2, 3, 5, 7, 11, 13, 17, 19] + @eprog\noindent If the argument $x$ is omitted, creates an empty map, which + may be filled later via \tet{mapput}. + +Function: Mat +Class: basic +Section: conversions +C-Name: gtomat +Prototype: DG +Help: Mat({x=[]}): transforms any GEN x into a matrix. Empty matrix if x is + omitted. +Description: + ():vec cgetg(1, t_MAT) + (gen):vec gtomat($1) +Doc: + transforms the object $x$ into a matrix. + If $x$ is already a matrix, a copy of $x$ is created. + If $x$ is a row (resp. column) vector, this creates a 1-row (resp. + 1-column) matrix, \emph{unless} all elements are column (resp.~row) vectors + of the same length, in which case the vectors are concatenated sideways + and the attached big matrix is returned. + If $x$ is a binary quadratic form, creates the attached $2\times 2$ + matrix. Otherwise, this creates a $1\times 1$ matrix containing $x$. + + \bprog + ? Mat(x + 1) + %1 = + [x + 1] + ? Vec( matid(3) ) + %2 = [[1, 0, 0]~, [0, 1, 0]~, [0, 0, 1]~] + ? Mat(%) + %3 = + [1 0 0] + + [0 1 0] + + [0 0 1] + ? Col( [1,2; 3,4] ) + %4 = [[1, 2], [3, 4]]~ + ? Mat(%) + %5 = + [1 2] + + [3 4] + ? Mat(Qfb(1,2,3)) + %6 = + [1 1] + + [1 3] + @eprog + +Function: Mod +Class: basic +Section: conversions +C-Name: gmodulo +Prototype: GG +Help: Mod(a,b): create 'a modulo b'. +Description: + (small, small):gen gmodulss($1, $2) + (small, gen):gen gmodulsg($1, $2) + (gen, gen):gen gmodulo($1, $2) +Doc: in its basic form, create an intmod or a polmod $(a \mod b)$; $b$ must + be an integer or a polynomial. We then obtain a \typ{INTMOD} and a + \typ{POLMOD} respectively: + \bprog + ? t = Mod(2,17); t^8 + %1 = Mod(1, 17) + ? t = Mod(x,x^2+1); t^2 + %2 = Mod(-1, x^2+1) + @eprog\noindent If $a \% b$ makes sense and yields a result of the + appropriate type (\typ{INT} or scalar/\typ{POL}), the operation succeeds as + well: + \bprog + ? Mod(1/2, 5) + %3 = Mod(3, 5) + ? Mod(7 + O(3^6), 3) + %4 = Mod(1, 3) + ? Mod(Mod(1,12), 9) + %5 = Mod(1, 3) + ? Mod(1/x, x^2+1) + %6 = Mod(-x, x^2+1) + ? Mod(exp(x), x^4) + %7 = Mod(1/6*x^3 + 1/2*x^2 + x + 1, x^4) + @eprog + If $a$ is a complex object, ``base change'' it to $\Z/b\Z$ or $K[x]/(b)$, + which is equivalent to, but faster than, multiplying it by \kbd{Mod(1,b)}: + \bprog + ? Mod([1,2;3,4], 2) + %8 = + [Mod(1, 2) Mod(0, 2)] + + [Mod(1, 2) Mod(0, 2)] + ? Mod(3*x+5, 2) + %9 = Mod(1, 2)*x + Mod(1, 2) + ? Mod(x^2 + y*x + y^3, y^2+1) + %10 = Mod(1, y^2 + 1)*x^2 + Mod(y, y^2 + 1)*x + Mod(-y, y^2 + 1) + @eprog + + This function is not the same as $x$ \kbd{\%} $y$, the result of which + has no knowledge of the intended modulus $y$. Compare + \bprog + ? x = 4 % 5; x + 1 + %11 = 5 + ? x = Mod(4,5); x + 1 + %12 = Mod(0,5) + @eprog Note that such ``modular'' objects can be lifted via \tet{lift} or + \tet{centerlift}. The modulus of a \typ{INTMOD} or \typ{POLMOD} $z$ can + be recovered via \kbd{$z$.mod}. + +Function: O +Class: basic +Section: polynomials +C-Name: ggrando +Prototype: +Help: O(p^e): p-adic or power series zero with precision given by e. +Doc: if $p$ is an integer + greater than $2$, returns a $p$-adic $0$ of precision $e$. In all other + cases, returns a power series zero with precision given by $e v$, where $v$ + is the $X$-adic valuation of $p$ with respect to its main variable. +Variant: \fun{GEN}{zeropadic}{GEN p, long e} for a $p$-adic and + \fun{GEN}{zeroser}{long v, long e} for a power series zero in variable $v$. + +Function: O(_^_) +Class: basic +Section: programming/internals +C-Name: ggrando +Prototype: GD1,L, +Help: O(p^e): p-adic or power series zero with precision given by e. +Description: + (gen):gen ggrando($1, 1) + (1,small):gen ggrando(gen_1, $2) + (int,small):gen zeropadic($1, $2) + (gen,small):gen ggrando($1, $2) + (var,small):gen zeroser($1, $2) + +Function: Pi +Class: basic +Section: transcendental +C-Name: mppi +Prototype: p +Help: Pi=Pi(): the constant pi, with current precision. +Description: + ():real:prec mppi($prec) +Doc: the constant $\pi$ ($3.14159\cdots$). Note that \kbd{Pi} is one of the few + reserved names which cannot be used for user variables. + +Function: Pol +Class: basic +Section: conversions +C-Name: gtopoly +Prototype: GDn +Help: Pol(t,{v='x}): convert t (usually a vector or a power series) into a + polynomial with variable v, starting with the leading coefficient. +Description: + (gen,?var):pol gtopoly($1, $2) +Doc: + transforms the object $t$ into a polynomial with main variable $v$. If $t$ + is a scalar, this gives a constant polynomial. If $t$ is a power series with + nonnegative valuation or a rational function, the effect is similar to + \kbd{truncate}, i.e.~we chop off the $O(X^{k})$ or compute the Euclidean + quotient of the numerator by the denominator, then change the main variable + of the result to $v$. + + The main use of this function is when $t$ is a vector: it creates the + polynomial whose coefficients are given by $t$, with $t[1]$ being the leading + coefficient (which can be zero). It is much faster to evaluate + \kbd{Pol} on a vector of coefficients in this way, than the corresponding + formal expression $a_{n} X^{n} + \dots + a_{0}$, which is evaluated naively + exactly as written (linear versus quadratic time in $n$). \tet{Polrev} can be + used if one wants $x[1]$ to be the constant coefficient: + \bprog + ? Pol([1,2,3]) + %1 = x^2 + 2*x + 3 + ? Polrev([1,2,3]) + %2 = 3*x^2 + 2*x + 1 + @eprog\noindent + The reciprocal function of \kbd{Pol} (resp.~\kbd{Polrev}) is \kbd{Vec} (resp.~ + \kbd{Vecrev}). + \bprog + ? Vec(Pol([1,2,3])) + %1 = [1, 2, 3] + ? Vecrev( Polrev([1,2,3]) ) + %2 = [1, 2, 3] + @eprog\noindent + + \misctitle{Warning} This is \emph{not} a substitution function. It will not + transform an object containing variables of higher priority than~$v$. + \bprog + ? Pol(x + y, y) + *** at top-level: Pol(x+y,y) + *** ^---------- + *** Pol: variable must have higher priority in gtopoly. + @eprog + +Function: Polrev +Class: basic +Section: conversions +C-Name: gtopolyrev +Prototype: GDn +Help: Polrev(t,{v='x}): convert t (usually a vector or a power series) into a + polynomial with variable v, starting with the constant term. +Description: + (gen,?var):pol gtopolyrev($1, $2) +Doc: + transform the object $t$ into a polynomial + with main variable $v$. If $t$ is a scalar, this gives a constant polynomial. + If $t$ is a power series, the effect is identical to \kbd{truncate}, i.e.~it + chops off the $O(X^{k})$. + + The main use of this function is when $t$ is a vector: it creates the + polynomial whose coefficients are given by $t$, with $t[1]$ being the + constant term. \tet{Pol} can be used if one wants $t[1]$ to be the leading + coefficient: + \bprog + ? Polrev([1,2,3]) + %1 = 3*x^2 + 2*x + 1 + ? Pol([1,2,3]) + %2 = x^2 + 2*x + 3 + @eprog + The reciprocal function of \kbd{Pol} (resp.~\kbd{Polrev}) is \kbd{Vec} (resp.~ + \kbd{Vecrev}). + +Function: Qfb +Class: basic +Section: conversions +C-Name: Qfb0 +Prototype: GDGDG +Help: Qfb(a,{b},{c}): binary quadratic form a*x^2+b*x*y+c*y^2. +Doc: creates the binary quadratic form\sidx{binary quadratic form} + $ax^{2}+bxy+cy^{2}$. Negative definite forms are not implemented, + use their positive definite counterpart instead. + The syntax \kbd{Qfb(V)} is also allowed with $V$ being either + a \typ{VEC} $[a,b,c]$, a \typ{POL} $ax^{2}+bx+c$ or a \typ{MAT} + $[a,b_{0};b_{1},c]$ with $b_{0}+b_{1}=b$. + +Function: Ser +Class: basic +Section: conversions +C-Name: Ser0 +Prototype: GDnDGDP +Help: Ser(s,{v='x},{d=seriesprecision}): convert s into a power series with + variable v and precision d, starting with the constant coefficient. +Doc: transforms the object $s$ into a power series with main variable $v$ + ($x$ by default) and precision (number of significant terms) equal to + $d \geq 0$ ($d = \kbd{seriesprecision}$ by default). If $s$ is a + scalar, this gives a constant power series in $v$ with precision \kbd{d}. + If $s$ is a polynomial, the polynomial is truncated to $d$ terms if needed + \bprog + ? \ps + seriesprecision = 16 significant terms + ? Ser(1) \\ 16 terms by default + %1 = 1 + O(x^16) + ? Ser(1, 'y, 5) + %2 = 1 + O(y^5) + ? Ser(x^2,, 5) + %3 = x^2 + O(x^7) + ? T = polcyclo(100) + %4 = x^40 - x^30 + x^20 - x^10 + 1 + ? Ser(T, 'x, 11) + %5 = 1 - x^10 + O(x^11) + @eprog\noindent The function is more or less equivalent with multiplication by + $1 + O(v^{d})$ in theses cases, only faster. + + For the remaining types, vectors and power series, we first explain what + occurs if $d$ is omitted. In this case, the function uses exactly the amount + of information given in the input: + + \item If $s$ is already a power series in $v$, we return it verbatim; + + \item If $s$ is a vector, the coefficients of the vector are + understood to be the coefficients of the power series starting from the + constant term (as in \tet{Polrev}$(x)$); in other words we convert + \typ{VEC} / \typ{COL} to the power series whose significant terms are exactly + given by the vector entries. + + On the other hand, if $d$ is explicitly given, we abide by its value + and return a series, truncated or extended with zeros as needed, with + $d$ significant terms. + + \bprog + ? v = [1,2,3]; + ? Ser(v, t) \\ 3 terms: seriesprecision is ignored! + %7 = 1 + 2*t + 3*t^2 + O(t^3) + ? Ser(v, t, 7) \\ 7 terms as explicitly requested + %8 = 1 + 2*t + 3*t^2 + O(t^7) + ? s = 1+x+O(x^2); + ? Ser(s) + %10 = 1 + x + O(x^2) \\ 2 terms: seriesprecision is ignored + ? Ser(s, x, 7) \\ extend to 7 terms + %11 = 1 + x + O(x^7) + ? Ser(s, x, 1) \\ truncate to 1 term + %12 = 1 + O(x) + @eprog\noindent + The warning given for \kbd{Pol} also applies here: this is not a substitution + function. + +Function: Set +Class: basic +Section: conversions +C-Name: gtoset +Prototype: DG +Help: Set({x=[]}): convert x into a set, i.e. a row vector with strictly + increasing coefficients. Empty set if x is omitted. +Description: + ():vec cgetg(1,t_VEC) + (gen):vec gtoset($1) +Doc: + converts $x$ into a set, i.e.~into a row vector, with strictly increasing + entries with respect to the (somewhat arbitrary) universal comparison function + \tet{cmp}. Standard container types \typ{VEC}, \typ{COL}, \typ{LIST} and + \typ{VECSMALL} are converted to the set with corresponding elements. All + others are converted to a set with one element. + \bprog + ? Set([1,2,4,2,1,3]) + %1 = [1, 2, 3, 4] + ? Set(x) + %2 = [x] + ? Set(Vecsmall([1,3,2,1,3])) + %3 = [1, 2, 3] + @eprog + +Function: Str +Class: basic +Section: conversions +C-Name: Str +Prototype: s* +Help: Str({x}*): concatenates its (string) argument into a single string. +Description: + (gen):genstr:copy:parens $genstr:1 + (gen,gen):genstr Str(mkvec2($1, $2)) + (gen,gen,gen):genstr Str(mkvec3($1, $2, $3)) + (gen,gen,gen,gen):genstr Str(mkvec4($1, $2, $3, $4)) + (gen,...):genstr Str(mkvecn($#, $2)) +Doc: + converts its argument list into a + single character string (type \typ{STR}, the empty string if $x$ is omitted). + To recover an ordinary \kbd{GEN} from a string, apply \kbd{eval} to it. The + arguments of \kbd{Str} are evaluated in string context, see \secref{se:strings}. + + \bprog + ? x2 = 0; i = 2; Str(x, i) + %1 = "x2" + ? eval(%) + %2 = 0 + @eprog\noindent + This function is mostly useless in library mode. Use the pair + \tet{strtoGEN}/\tet{GENtostr} to convert between \kbd{GEN} and \kbd{char*}. + The latter returns a malloced string, which should be freed after usage. + +Function: Strchr +Class: basic +Section: programming/specific +C-Name: pari_strchr +Prototype: G +Obsolete: 2018-10-01 +Help: Strchr(x): deprecated alias for strchr. +Doc: deprecated alias for strchr. + +Function: Strexpand +Class: basic +Section: programming/specific +C-Name: strexpand +Prototype: s* +Obsolete: 2018-10-01 +Help: Strexpand({x}*): deprecated alias for strexpand +Doc: deprecated alias for strexpand + +Function: Strprintf +Class: basic +Section: programming/specific +C-Name: strprintf +Prototype: ss* +Obsolete: 2018-10-01 +Help: Strprintf(fmt,{x}*): deprecated alias for strprintf. +Doc: deprecated alias for strprintf. + +Function: Strtex +Class: basic +Section: programming/specific +C-Name: strtex +Prototype: s* +Obsolete: 2018-10-01 +Help: Strtex({x}*): deprecated alias for strtex. +Doc: deprecated alias for strtex. + +Function: Vec +Class: basic +Section: conversions +C-Name: gtovec0 +Prototype: GD0,L, +Help: Vec(x,{n}): transforms the object x into a vector of dimension n. +Description: + (gen):vec gtovec($1) +Doc: transforms the object $x$ into a row vector. The dimension of the + resulting vector can be optionally specified via the extra parameter $n$. + If $n$ is omitted or $0$, the dimension depends on the type of $x$; the + vector has a single component, except when $x$ is + + \item a vector or a quadratic form: returns the initial object considered as a + row vector, + + \item a polynomial or a power series: returns a vector consisting of the + coefficients. In the case of a polynomial, the coefficients of the vector + start with the leading coefficient of the polynomial, while for power series + only the significant coefficients are taken into account, but this time by + increasing order of degree. In particular the valuation is ignored + (which makes the function useful for series of negative valuation): + \bprog + ? Vec(3*x^2 + x) + %1 = [3, 1, 0] + ? Vec(x^2 + 3*x^3 + O(x^5)) + %2 = [1, 3, 0] + ? Vec(x^-2 + 3*x^-1 + O(x)) + %3 = [1, 3, 0] + @eprog\noindent \kbd{Vec} is the reciprocal function of \kbd{Pol} for a + polynomial and of \kbd{Ser} for power series of valuation $0$. + + \item a matrix: returns the vector of columns comprising the matrix, + \bprog + ? m = [1,2,3;4,5,6] + %4 = + [1 2 3] + + [4 5 6] + ? Vec(m) + %5 = [[1, 4]~, [2, 5]~, [3, 6]~] + @eprog + + \item a character string: returns the vector of individual characters + (as strings of length $1$), + \bprog + ? Vec("PARI") + %6 = ["P", "A", "R", "I"] + @eprog + + \item a map: returns the vector of the domain of the map, + + \item an error context (\typ{ERROR}): returns the error components, see + \tet{iferr}. + + In the last four cases (matrix, character string, map, error), $n$ is + meaningless and must be omitted or an error is raised. Otherwise, if $n$ is + given, $0$ entries are appended at the end of the vector if $n > 0$, and + prepended at the beginning if $n < 0$. The dimension of the resulting vector + is $|n|$. If the original object had fewer than $|n|$ components, it is + truncated from the right if $n > 0$ and from the left if $n < 0$: + \bprog + ? v = [1,2,3,4]; + ? forstep(i=5, 2, -1, print(Vec(v, i))); + [1, 2, 3, 4, 0] + [1, 2, 3, 4] + [1, 2, 3] \\ truncated from the right + [1, 2] + + ? forstep(i=5, 2, -1, print(Vec(v, -i))); + [0, 1, 2, 3, 4] + [1, 2, 3, 4] + [2, 3, 4] \\ truncated from the left + [3, 4] + @eprog + + These rules allow to write a conversion function for series that takes + positive valuations into account: + \bprog + ? serVec(s) = Vec(s, -serprec(s,variable(s))); + ? serVec(x^2 + 3*x^3 + O(x^5)) + %2 = [0, 0, 1, 3, 0] + @eprog\noindent (That function is not intended for series of negative + valuation.) +Variant: \fun{GEN}{gtovec}{GEN x} is also available. + +Function: Vecrev +Class: basic +Section: conversions +C-Name: gtovecrev0 +Prototype: GD0,L, +Help: Vecrev(x,{n}): transforms the object x into a vector of dimension n + in reverse order with respect to Vec(x,{n}). +Description: + (gen):vec gtovecrev($1) +Doc: + as $\kbd{Vec}(x, -n)$, then reverse the result. In particular, + \kbd{Vecrev} is the reciprocal function of \kbd{Polrev}: the + coefficients of the vector start with the constant coefficient of the + polynomial and the others follow by increasing degree. +Variant: \fun{GEN}{gtovecrev}{GEN x} is also available. + +Function: Vecsmall +Class: basic +Section: conversions +C-Name: gtovecsmall0 +Prototype: GD0,L, +Help: Vecsmall(x,{n}): transforms the object x into a VECSMALL of dimension n. +Description: + (gen,?0):vecsmall gtovecsmall($1) + (gen,small):vecsmall gtovecsmall0($1, $2) +Doc: + transforms the object $x$ into a row vector of type \typ{VECSMALL}. The + dimension of the resulting vector can be optionally specified via the extra + parameter $n$. + + This acts as \kbd{Vec}$(x,n)$, but only on a limited set of objects: + the result must be representable as a vector of small integers. + If $x$ is a character string, a vector of individual characters in ASCII + encoding is returned (\tet{strchr} yields back the character string). +Variant: \fun{GEN}{gtovecsmall}{GEN x} is also available. + +Function: [_.._] +Class: basic +Section: programming/internals +C-Name: vecrange +Prototype: GG +Help: [a..b] = [a,a+1,...,b] +Description: + (gen,gen):vec vecrange($1, $2) + (small,small):vec vecrangess($1, $2) + +Function: [_|_<-_,_;_] +Class: basic +Section: programming/internals +C-Name: vecexpr1 +Prototype: mGVDEDE +Help: [a(x)|x<-b,c(x);...] +Wrapper: (,,G,bG) +Description: + (gen,,closure):gen veccatapply(${3 cookie}, ${3 wrapper}, $1) + (gen,,closure,closure):gen veccatselapply(${4 cookie}, ${4 wrapper}, ${3 cookie}, ${3 wrapper}, $1) + +Function: [_|_<-_,_] +Class: basic +Section: programming/internals +C-Name: vecexpr0 +Prototype: GVDEDE +Help: [a(x)|x<-b,c(x)] = apply(a,select(c,b)) +Wrapper: (,,G,bG) +Description: + (gen,,closure):gen vecapply(${3 cookie}, ${3 wrapper}, $1) + (gen,,,closure):gen vecselect(${4 cookie}, ${4 wrapper}, $1) + (gen,,closure,closure):gen vecselapply(${4 cookie}, ${4 wrapper}, ${3 cookie}, ${3 wrapper}, $1) + +Function: _! +Class: basic +Section: symbolic_operators +C-Name: mpfact +Prototype: L +Help: n!: factorial of n. +Description: + (small):int mpfact($1) + +Function: _!=_ +Class: basic +Section: symbolic_operators +C-Name: gne +Prototype: GG +Help: a!=b: true if a and b are not equal. +Description: + (small, small):bool:parens $(1) != $(2) + (lg, lg):bool:parens $(1) != $(2) + (small, int):negbool equalsi($1, $2) + (int, small):negbool equalis($1, $2) + (int, 1):negbool equali1($1) + (int, -1):negbool equalim1($1) + (int, int):negbool equalii($1, $2) + (real,real):negbool equalrr($1, $2) + (mp, mp):bool:parens mpcmp($1, $2) != 0 + (errtyp, errtyp):bool:parens $(1) != $(2) + (errtyp, #str):bool:parens $(1) != $(errtyp:2) + (#str, errtyp):bool:parens $(errtyp:1) != $(2) + (typ, typ):bool:parens $(1) != $(2) + (typ, #str):bool:parens $(1) != $(typ:2) + (#str, typ):bool:parens $(typ:1) != $(2) + (str, str):bool strcmp($1, $2) + (small, gen):negbool gequalsg($1, $2) + (gen, small):negbool gequalgs($1, $2) + (gen, gen):negbool gequal($1, $2) + +Function: _# +Class: basic +Section: symbolic_operators +C-Name: mpprimorial +Prototype: L +Help: n#: primorial of n. +Description: + (small):int mpprimorial($1) + +Function: _%=_ +Class: basic +Section: symbolic_operators +C-Name: gmode +Prototype: &G +Help: x%=y: shortcut for x=x%y. +Description: + (*small, small):small:parens $1 = smodss($1, $2) + (*int, small):int:parens $1 = modis($1, $2) + (*int, int):int:parens $1 = modii($1, $2) + (*pol, gen):gen:parens $1 = gmod($1, $2) + (*gen, small):gen:parens $1 = gmodgs($1, $2) + (*gen, gen):gen:parens $1 = gmod($1, $2) + +Function: _%_ +Class: basic +Section: symbolic_operators +C-Name: gmod +Prototype: GG +Help: x%y: Euclidean remainder of x and y. +Description: + (small, small):small smodss($1, $2) + (small, int):int modsi($1, $2) + (int, small):small smodis($1, $2) + (int, int):int modii($1, $2) + (gen, small):gen gmodgs($1, $2) + (small, gen):gen gmodsg($1, $2) + (gen, gen):gen gmod($1, $2) + + (FpX,FpX):FpX FpX_rem($1, $2, p) + (FqX,FqX):FqX FqX_rem($1, $2, T, p) + +Function: _&&_ +Class: basic +Section: symbolic_operators +C-Name: andpari +Prototype: GE +Help: a&&b: boolean operator "and". +Description: + (bool, bool):bool:parens $(1) && $(2) + +Function: _' +Class: basic +Section: symbolic_operators +C-Name: deriv +Prototype: GDn +Help: x': derivative of x with respect to the main variable. + +Function: _'_ +Class: basic +Section: symbolic_operators +C-Name: derivn +Prototype: GLDn +Help: x': derivative of x with respect to the main variable. +Description: + (gen,1):gen deriv($1, -1) + + (FpX,1):FpX FpX_deriv($1, p) + (FqX,1):FqX FqX_deriv($1, T, p) + +Function: _(_) +Class: basic +Section: symbolic_operators +Help: f(a,b,...): evaluate the function f on a,b,... +Description: + (gen):gen closure_callgenall($1, 0) + (gen,gen):gen closure_callgen1($1, $2) + (gen,gen,gen):gen closure_callgen2($1, $2, $3) + (gen,gen,...):gen closure_callgenall($1, ${nbarg 1 sub}, $3) + +Function: _*=_ +Class: basic +Section: symbolic_operators +C-Name: gmule +Prototype: &G +Help: x*=y: shortcut for x=x*y. +Description: + (*small, small):small:parens $1 *= $(2) + (*int, small):int:parens $1 = mulis($1, $2) + (*int, int):int:parens $1 = mulii($1, $2) + (*real, small):real:parens $1 = mulrs($1, $2) + (*real, int):real:parens $1 = mulri($1, $2) + (*real, real):real:parens $1 = mulrr($1, $2) + (*mp, mp):mp:parens $1 = mpmul($1, $2) + (*pol, small):gen:parens $1 = gmulgs($1, $2) + (*pol, gen):gen:parens $1 = gmul($1, $2) + (*vec, gen):gen:parens $1 = gmul($1, $2) + (*gen, small):gen:parens $1 = gmulgs($1, $2) + (*gen, gen):gen:parens $1 = gmul($1, $2) + +Function: _*_ +Class: basic +Section: symbolic_operators +C-Name: gmul +Prototype: GG +Help: x*y: product of x and y. +Description: + (small, small):small:parens $(1)*$(2) + (int, small):int mulis($1, $2) + (small, int):int mulsi($1, $2) + (int, int):int mulii($1, $2) + (0, mp):small ($2, 0)/*for side effect*/ + (#small, real):real mulsr($1, $2) + (small, real):mp gmulsg($1, $2) + (mp, 0):small ($1, 0)/*for side effect*/ + (real, #small):real mulrs($1, $2) + (real, small):mp gmulgs($1, $2) + (real, real):real mulrr($1, $2) + (mp, mp):mp gmul($1, $2) + (gen, small):gen gmulgs($1, $2) + (small, gen):gen gmulsg($1, $2) + (vecsmall, vecsmall):vecsmall perm_mul($1, $2) + (gen, gen):gen gmul($1, $2) + + (usmall,Fp):Fp Fp_mulu($2, $1, p) + (small,Fp):Fp Fp_muls($2, $1, p) + (Fp, usmall):Fp Fp_mulu($1, $2, p) + (Fp, small):Fp Fp_muls($1, $2, p) + (usmall,FpX):FpX FpX_mulu($2, $1, p) + (FpX, usmall):FpX FpX_mulu($1, $2, p) + (Fp, FpX):FpX FpX_Fp_mul($2, $1, p) + (FpX, Fp):FpX FpX_Fp_mul($1, $2, p) + (FpX, FpX):FpX FpX_mul($1, $2, p) + + (usmall,Fq):Fq Fq_mulu($2, $1, T, p) + (Fq, usmall):Fq Fq_mulu($1, $2, T, p) + (Fq,Fp):Fq Fq_Fp_mul($1, $2, T, p) + (Fp,Fq):Fq Fq_Fp_mul($2, $1, T, p) + (usmall,FqX):FqX FqX_mulu($2, $1, T, p) + (FqX, usmall):FqX FqX_mulu($1, $2, T, p) + (FqX,Fp):FqX FqX_Fp_mul($1, $2, T, p) + (Fp,FqX):FqX FqX_Fp_mul($2, $1, T, p) + (Fq, FqX):FqX FqX_Fq_mul($2, $1, T, p) + (FqX, Fq):FqX FqX_Fq_mul($1, $2, T, p) + (FqX, FqX):FqX FqX_mul($1, $2, T, p) + +Function: _++ +Class: basic +Section: symbolic_operators +C-Name: gadd1e +Prototype: & +Help: x++: set x to x+1. +Description: + (*bptr):bptr ++$1 + (*small):small ++$1 + (*lg):lg ++$1 + (*int):int:parens $1 = addis($1, 1) + (*real):real:parens $1 = addrs($1, 1) + (*mp):mp:parens $1 = mpadd($1, gen_1) + (*pol):pol:parens $1 = gaddgs($1, 1) + (*gen):gen:parens $1 = gaddgs($1, 1) + +Function: _+=_ +Class: basic +Section: symbolic_operators +C-Name: gadde +Prototype: &G +Help: x+=y: shortcut for x=x+y. +Description: + (*small, small):small:parens $1 += $(2) + (*lg, small):lg:parens $1 += $(2) + (*int, small):int:parens $1 = addis($1, $2) + (*int, int):int:parens $1 = addii($1, $2) + (*real, small):real:parens $1 = addrs($1, $2) + (*real, int):real:parens $1 = addir($2, $1) + (*real, real):real:parens $1 = addrr($1, $2) + (*mp, mp):mp:parens $1 = mpadd($1, $2) + (*pol, small):gen:parens $1 = gaddgs($1, $2) + (*pol, gen):gen:parens $1 = gadd($1, $2) + (*vec, gen):gen:parens $1 = gadd($1, $2) + (*gen, small):gen:parens $1 = gaddgs($1, $2) + (*gen, gen):gen:parens $1 = gadd($1, $2) + +Function: _+_ +Class: basic +Section: symbolic_operators +C-Name: gadd +Prototype: GG +Help: x+y: sum of x and y. +Description: + (lg, 1):small:parens $(1) + (small, small):small:parens $(1) + $(2) + (lg, small):lg:parens $(1) + $(2) + (small, lg):lg:parens $(1) + $(2) + (int, small):int addis($1, $2) + (small, int):int addsi($1, $2) + (int, int):int addii($1, $2) + (real, small):real addrs($1, $2) + (small, real):real addsr($1, $2) + (real, real):real addrr($1, $2) + (mp, real):real mpadd($1, $2) + (real, mp):real mpadd($1, $2) + (mp, mp):mp mpadd($1, $2) + (gen, small):gen gaddgs($1, $2) + (small, gen):gen gaddsg($1, $2) + (gen, gen):gen gadd($1, $2) + + (Fp, Fp):Fp Fp_add($1, $2, p) + (FpX, Fp):FpX FpX_Fp_add($1, $2, p) + (Fp, FpX):FpX FpX_Fp_add($2, $1, p) + (FpX, FpX):FpX FpX_add($1, $2, p) + (Fq, Fq):Fq Fq_add($1, $2, T, p) + (FqX, Fq):FqX FqX_Fq_add($1, $2, T, p) + (Fq, FqX):FqX FqX_Fq_add($2, $1, T, p) + (FqX, FqX):FqX FqX_add($1, $2, T, p) + +Function: _-- +Class: basic +Section: symbolic_operators +C-Name: gsub1e +Prototype: & +Help: x--: set x to x-1. +Description: + (*bptr):bptr --$1 + (*small):small --$1 + (*lg):lg --$1 + (*int):int:parens $1 = subis($1, 1) + (*real):real:parens $1 = subrs($1, 1) + (*mp):mp:parens $1 = mpsub($1, gen_1) + (*pol):pol:parens $1 = gsubgs($1, 1) + (*gen):gen:parens $1 = gsubgs($1, 1) + +Function: _-=_ +Class: basic +Section: symbolic_operators +C-Name: gsube +Prototype: &G +Help: x-=y: shortcut for x=x-y. +Description: + (*small, small):small:parens $1 -= $(2) + (*lg, small):lg:parens $1 -= $(2) + (*int, small):int:parens $1 = subis($1, $2) + (*int, int):int:parens $1 = subii($1, $2) + (*real, small):real:parens $1 = subrs($1, $2) + (*real, int):real:parens $1 = subri($1, $2) + (*real, real):real:parens $1 = subrr($1, $2) + (*mp, mp):mp:parens $1 = mpsub($1, $2) + (*pol, small):gen:parens $1 = gsubgs($1, $2) + (*pol, gen):gen:parens $1 = gsub($1, $2) + (*vec, gen):gen:parens $1 = gsub($1, $2) + (*gen, small):gen:parens $1 = gsubgs($1, $2) + (*gen, gen):gen:parens $1 = gsub($1, $2) + +Function: _-_ +Class: basic +Section: symbolic_operators +C-Name: gsub +Prototype: GG +Help: x-y: difference of x and y. +Description: + (small, small):small:parens $(1) - $(2) + (lg, small):lg:parens $(1) - $(2) + (int, small):int subis($1, $2) + (small, int):int subsi($1, $2) + (int, int):int subii($1, $2) + (real, small):real subrs($1, $2) + (small, real):real subsr($1, $2) + (real, real):real subrr($1, $2) + (mp, real):real mpsub($1, $2) + (real, mp):real mpsub($1, $2) + (mp, mp):mp mpsub($1, $2) + (gen, small):gen gsubgs($1, $2) + (small, gen):gen gsubsg($1, $2) + (gen, gen):gen gsub($1, $2) + + (Fp, Fp):Fp Fp_sub($1, $2, p) + (Fp, FpX):FpX Fp_FpX_sub($1, $2, p) + (FpX, Fp):FpX FpX_Fp_sub($1, $2, p) + (FpX, FpX):FpX FpX_sub($1, $2, p) + (Fq, Fq):Fq Fq_sub($1, $2, T, p) + (FqX, Fq):FqX FqX_Fq_sub($1, $2, T, p) + (FqX, FqX):FqX FqX_sub($1, $2, T, p) + +Function: _.a1 +Class: basic +Section: member_functions +C-Name: member_a1 +Prototype: mG +Help: _.a1 +Description: + (ell):gen:copy ell_get_a1($1) + +Function: _.a2 +Class: basic +Section: member_functions +C-Name: member_a2 +Prototype: mG +Help: _.a2 +Description: + (ell):gen:copy ell_get_a2($1) + +Function: _.a3 +Class: basic +Section: member_functions +C-Name: member_a3 +Prototype: mG +Help: _.a3 +Description: + (ell):gen:copy ell_get_a3($1) + +Function: _.a4 +Class: basic +Section: member_functions +C-Name: member_a4 +Prototype: mG +Help: _.a4 +Description: + (ell):gen:copy ell_get_a4($1) + +Function: _.a6 +Class: basic +Section: member_functions +C-Name: member_a6 +Prototype: mG +Help: _.a6 +Description: + (ell):gen:copy ell_get_a6($1) + +Function: _.area +Class: basic +Section: member_functions +C-Name: member_area +Prototype: mG +Help: _.area + +Function: _.b2 +Class: basic +Section: member_functions +C-Name: member_b2 +Prototype: mG +Help: _.b2 +Description: + (ell):gen:copy ell_get_b2($1) + +Function: _.b4 +Class: basic +Section: member_functions +C-Name: member_b4 +Prototype: mG +Help: _.b4 +Description: + (ell):gen:copy ell_get_b4($1) + +Function: _.b6 +Class: basic +Section: member_functions +C-Name: member_b6 +Prototype: mG +Help: _.b6 +Description: + (ell):gen:copy ell_get_b6($1) + +Function: _.b8 +Class: basic +Section: member_functions +C-Name: member_b8 +Prototype: mG +Help: _.b8 +Description: + (ell):gen:copy ell_get_b8($1) + +Function: _.bid +Class: basic +Section: member_functions +C-Name: member_bid +Prototype: mG +Help: _.bid +Description: + (bnr):gen:copy bnr_get_bid($1) + (gen):gen:copy member_bid($1) + +Function: _.bnf +Class: basic +Section: member_functions +C-Name: member_bnf +Prototype: mG +Help: _.bnf +Description: + (bnf):bnf:parens $1 + (bnr):bnf:copy:parens $bnf:1 + (gen):bnf:copy member_bnf($1) + +Function: _.c4 +Class: basic +Section: member_functions +C-Name: member_c4 +Prototype: mG +Help: _.c4 +Description: + (ell):gen:copy ell_get_c4($1) + +Function: _.c6 +Class: basic +Section: member_functions +C-Name: member_c6 +Prototype: mG +Help: _.c6 +Description: + (ell):gen:copy ell_get_c6($1) + +Function: _.clgp +Class: basic +Section: member_functions +C-Name: member_clgp +Prototype: mG +Help: _.clgp +Description: + (bnf):clgp:copy:parens $clgp:1 + (bnr):clgp:copy:parens $clgp:1 + (clgp):clgp:parens $1 + (gen):clgp:copy member_clgp($1) + +Function: _.codiff +Class: basic +Section: member_functions +C-Name: member_codiff +Prototype: mG +Help: _.codiff + +Function: _.cyc +Class: basic +Section: member_functions +C-Name: member_cyc +Prototype: mG +Help: _.cyc +Description: + (bnr):vec:copy bnr_get_cyc($1) + (bnf):vec:copy bnf_get_cyc($1) + (clgp):vec:copy gel($1, 2) + (gen):vec:copy member_cyc($1) + +Function: _.diff +Class: basic +Section: member_functions +C-Name: member_diff +Prototype: mG +Help: _.diff +Description: + (nf):gen:copy nf_get_diff($1) + (gen):gen:copy member_diff($1) + +Function: _.disc +Class: basic +Section: member_functions +C-Name: member_disc +Prototype: mG +Help: _.disc +Description: + (nf):int:copy nf_get_disc($1) + (ell):gen:copy ell_get_disc($1) + (gen):gen:copy member_disc($1) + +Function: _.e +Class: basic +Section: member_functions +C-Name: member_e +Prototype: mG +Help: _.e +Description: + (prid):small pr_get_e($1) + +Function: _.eta +Class: basic +Section: member_functions +C-Name: member_eta +Prototype: mG +Help: _.eta + +Function: _.f +Class: basic +Section: member_functions +C-Name: member_f +Prototype: mG +Help: _.f +Description: + (prid):small pr_get_f($1) + +Function: _.fu +Class: basic +Section: member_functions +C-Name: member_fu +Prototype: G +Help: _.fu +Description: + (bnr):void $"ray units not implemented" + (bnf):gen:copy bnf_get_fu($1) + (gen):gen member_fu($1) + +Function: _.gen +Class: basic +Section: member_functions +C-Name: member_gen +Prototype: mG +Help: _.gen +Description: + (bnr):vec:copy bnr_get_gen($1) + (bnf):vec:copy bnf_get_gen($1) + (gal):vecvecsmall:copy gal_get_gen($1) + (clgp):vec:copy gel($1, 3) + (prid):gen:copy pr_get_gen($1) + (gen):gen:copy member_gen($1) + +Function: _.group +Class: basic +Section: member_functions +C-Name: member_group +Prototype: mG +Help: _.group +Description: + (gal):vecvecsmall:copy gal_get_group($1) + (gen):vecvecsmall:copy member_group($1) + +Function: _.index +Class: basic +Section: member_functions +C-Name: member_index +Prototype: mG +Help: _.index +Description: + (nf):int:copy nf_get_index($1) + (gen):int:copy member_index($1) + +Function: _.j +Class: basic +Section: member_functions +C-Name: member_j +Prototype: mG +Help: _.j +Description: + (ell):gen:copy ell_get_j($1) + +Function: _.mod +Class: basic +Section: member_functions +C-Name: member_mod +Prototype: mG +Help: _.mod + +Function: _.nf +Class: basic +Section: member_functions +C-Name: member_nf +Prototype: mG +Help: _.nf +Description: + (nf):nf:parens $1 + (gen):nf:copy member_nf($1) + +Function: _.no +Class: basic +Section: member_functions +C-Name: member_no +Prototype: mG +Help: _.no +Description: + (bnr):int:copy bnr_get_no($1) + (bnf):int:copy bnf_get_no($1) + (clgp):int:copy gel($1, 1) + (gen):int:copy member_no($1) + +Function: _.normfu +Class: basic +Section: member_functions +C-Name: member_normfu +Prototype: mG +Help: _.normfu + +Function: _.omega +Class: basic +Section: member_functions +C-Name: member_omega +Prototype: mG +Help: _.omega + +Function: _.orders +Class: basic +Section: member_functions +C-Name: member_orders +Prototype: mG +Help: _.orders +Description: + (gal):vecsmall:copy gal_get_orders($1) + +Function: _.p +Class: basic +Section: member_functions +C-Name: member_p +Prototype: mG +Help: _.p +Description: + (gal):int:copy gal_get_p($1) + (prid):int:copy pr_get_p($1) + (gen):int:copy member_p($1) + +Function: _.pol +Class: basic +Section: member_functions +C-Name: member_pol +Prototype: mG +Help: _.pol +Description: + (gal):gen:copy gal_get_pol($1) + (nf):gen:copy nf_get_pol($1) + (gen):gen:copy member_pol($1) + +Function: _.polabs +Class: basic +Section: member_functions +C-Name: member_polabs +Prototype: mG +Help: _.polabs + +Function: _.r1 +Class: basic +Section: member_functions +C-Name: member_r1 +Prototype: mG +Help: _.r1 +Description: + (nf):small nf_get_r1($1) + (gen):int:copy member_r1($1) + +Function: _.r2 +Class: basic +Section: member_functions +C-Name: member_r2 +Prototype: mG +Help: _.r2 +Description: + (nf):small nf_get_r2($1) + (gen):int:copy member_r2($1) + +Function: _.reg +Class: basic +Section: member_functions +C-Name: member_reg +Prototype: mG +Help: _.reg +Description: + (bnr):real $"ray regulator not implemented" + (bnf):real:copy bnf_get_reg($1) + (gen):real:copy member_reg($1) + +Function: _.roots +Class: basic +Section: member_functions +C-Name: member_roots +Prototype: mG +Help: _.roots +Description: + (gal):vec:copy gal_get_roots($1) + (nf):vec:copy nf_get_roots($1) + (gen):vec:copy member_roots($1) + +Function: _.sign +Class: basic +Section: member_functions +C-Name: member_sign +Prototype: mG +Help: _.sign +Description: + (nf):vec:copy gel($1, 2) + (gen):vec:copy member_sign($1) + +Function: _.t2 +Class: basic +Section: member_functions +C-Name: member_t2 +Prototype: G +Help: _.t2 +Description: + (gen):vec member_t2($1) + +Function: _.tate +Class: basic +Section: member_functions +C-Name: member_tate +Prototype: mG +Help: _.tate + +Function: _.tu +Class: basic +Section: member_functions +C-Name: member_tu +Prototype: G +Help: _.tu +Description: + (gen):gen:copy member_tu($1) + +Function: _.zk +Class: basic +Section: member_functions +C-Name: member_zk +Prototype: mG +Help: _.zk +Description: + (nf):vec:copy nf_get_zk($1) + (gen):vec:copy member_zk($1) + +Function: _.zkst +Class: basic +Section: member_functions +C-Name: member_zkst +Prototype: mG +Help: _.zkst +Description: + (bnr):gen:copy bnr_get_bid($1) + +Function: _/=_ +Class: basic +Section: symbolic_operators +C-Name: gdive +Prototype: &G +Help: x/=y: shortcut for x=x/y. +Description: + (*small, gen):void $"cannot divide small: use \= instead." + (*int, gen):void $"cannot divide int: use \= instead." + (*real, real):real:parens $1 = divrr($1, $2) + (*real, small):real:parens $1 = divrs($1, $2) + (*real, mp):real:parens $1 = mpdiv($1, $2) + (*mp, real):mp:parens $1 = mpdiv($1, $2) + (*pol, gen):gen:parens $1 = gdiv($1, $2) + (*vec, gen):gen:parens $1 = gdiv($1, $2) + (*gen, small):gen:parens $1 = gdivgs($1, $2) + (*gen, gen):gen:parens $1 = gdiv($1, $2) + +Function: _/_ +Class: basic +Section: symbolic_operators +C-Name: gdiv +Prototype: GG +Help: x/y: quotient of x and y. +Description: + (0, mp):small ($2, 0)/*for side effect*/ + (1, real):real invr($2) + (#small, real):real divsr($1, $2) + (small, real):mp divsr($1, $2) + (real, small):real divrs($1, $2) + (real, real):real divrr($1, $2) + (real, mp):real mpdiv($1, $2) + (mp, real):mp mpdiv($1, $2) + (1, gen):gen ginv($2) + (gen, small):gen gdivgs($1, $2) + (small, gen):gen gdivsg($1, $2) + (gen, gen):gen gdiv($1, $2) + + (Fp, 2):Fp Fp_halve($1, p) + (Fp, Fp):Fp Fp_div($1, $2, p) + (Fq, 2):Fq Fq_halve($1, T, p) + (Fq, Fq):Fq Fq_div($1, $2, T, p) + +Function: _<<=_ +Class: basic +Section: symbolic_operators +C-Name: gshiftle +Prototype: &L +Help: x<<=y: shortcut for x=x<=_ +Class: basic +Section: symbolic_operators +C-Name: gge +Prototype: GG +Help: x>=y: return 1 if x is greater or equal to y, 0 otherwise. +Description: + (small, small):bool:parens $(1) >= $(2) + (lg, lg):bool:parens $(1) >= $(2) + (lg, small):bool:parens $(1) > $(2) + (small, int):bool:parens cmpsi($1, $2) >= 0 + (int, small):bool:parens cmpis($1, $2) >= 0 + (int, int):bool:parens cmpii($1, $2) >= 0 + (mp, mp):bool:parens mpcmp($1, $2) >= 0 + (str, str):bool:parens strcmp($1, $2) >= 0 + (small, gen):bool:parens gcmpsg($1, $2) >= 0 + (gen, small):bool:parens gcmpgs($1, $2) >= 0 + (gen, gen):bool:parens gcmp($1, $2) >= 0 + +Function: _>>=_ +Class: basic +Section: symbolic_operators +C-Name: gshiftre +Prototype: &L +Help: x>>=y: shortcut for x=x>>y. +Description: + (*small, small):small:parens $1 >>= $(2) + (*int, small):int:parens $1 = shifti($1, -$(2)) + (*mp, small):mp:parens $1 = mpshift($1, -$(2)) + (*gen, small):mp:parens $1 = gshift($1, -$(2)) + +Function: _>>_ +Class: basic +Section: symbolic_operators +C-Name: gshift_right +Prototype: GL +Help: x>>y: compute shift(x,-y). +Description: + (small, small):small:parens $(1)>>$(2) + (int, small):int shifti($1, -$(2)) + (mp, small):mp mpshift($1, -$(2)) + (gen, small):mp gshift($1, -$(2)) + +Function: _>_ +Class: basic +Section: symbolic_operators +C-Name: ggt +Prototype: GG +Help: x>y: return 1 if x is strictly greater than y, 0 otherwise. +Description: + (small, small):bool:parens $(1) > $(2) + (lg, lg):bool:parens $(1) > $(2) + (small, lg):bool:parens $(1) >= $(2) + (small, int):bool:parens cmpsi($1, $2) > 0 + (int, small):bool:parens cmpis($1, $2) > 0 + (int, int):bool:parens cmpii($1, $2) > 0 + (mp, mp):bool:parens mpcmp($1, $2) > 0 + (str, str):bool:parens strcmp($1, $2) > 0 + (small, gen):bool:parens gcmpsg($1, $2) > 0 + (gen, small):bool:parens gcmpgs($1, $2) > 0 + (gen, gen):bool:parens gcmp($1, $2) > 0 + +Function: _F2xq_log_Coppersmith_worker +Class: basic +Section: programming/internals +C-Name: F2xq_log_Coppersmith_worker +Prototype: GLGG +Help: F2xq_log_Coppersmith_worker: worker for F2xq_log_Coppersmith + +Function: _Flxq_log_Coppersmith_worker +Class: basic +Section: programming/internals +C-Name: Flxq_log_Coppersmith_worker +Prototype: GLGG +Help: Flxq_log_Coppersmith_worker: worker for Flxq_log_Coppersmith + +Function: _FpM_ratlift_worker +Class: basic +Section: programming/internals +C-Name: FpM_ratlift_worker +Prototype: GGG +Help: worker for FpM_ratlift + +Function: _Fp_log_sieve_worker +Class: basic +Section: programming/internals +C-Name: Fp_log_sieve_worker +Prototype: LLGGGGGG +Help: Fp_log_sieve_worker: worker for Fp_log_sieve + +Function: _QM_charpoly_ZX_worker +Class: basic +Section: programming/internals +C-Name: QM_charpoly_ZX_worker +Prototype: GGG +Help: worker for QM_charpoly_ZX + +Function: _QXQ_div_worker +Class: basic +Section: programming/internals +C-Name: QXQ_div_worker +Prototype: GGGG +Help: worker for QXQ_div + +Function: _QXQ_inv_worker +Class: basic +Section: programming/internals +C-Name: QXQ_inv_worker +Prototype: GGG +Help: worker for QXQ_inv + +Function: _RgM_ZM_mul_worker +Class: basic +Section: programming/internals +C-Name: RgM_ZM_mul_worker +Prototype: GG +Help: worker for RgM_ZM_mul + +Function: _ZM_det_worker +Class: basic +Section: programming/internals +C-Name: ZM_det_worker +Prototype: GG +Help: worker for ZM_det + +Function: _ZM_gauss_worker +Class: basic +Section: programming/internals +C-Name: ZM_gauss_worker +Prototype: GGG +Help: worker for ZM_gauss + +Function: _ZM_inv_worker +Class: basic +Section: programming/internals +C-Name: ZM_inv_worker +Prototype: GG +Help: worker for ZM_inv + +Function: _ZM_ker_worker +Class: basic +Section: programming/internals +C-Name: ZM_ker_worker +Prototype: GG +Help: worker for ZM_ker + +Function: _ZM_mul_worker +Class: basic +Section: programming/internals +C-Name: ZM_mul_worker +Prototype: GGG +Help: worker for ZM_mul + +Function: _ZM_sqr_worker +Class: basic +Section: programming/internals +C-Name: ZM_sqr_worker +Prototype: GG +Help: worker for ZM_sqr + +Function: _ZXQX_composedsum_worker +Class: basic +Section: programming/internals +C-Name: ZXQX_composedsum_worker +Prototype: GGGG +Help: worker for ZXQX_composedsum + +Function: _ZXQX_resultant_worker +Class: basic +Section: programming/internals +C-Name: ZXQX_resultant_worker +Prototype: GGGGG +Help: worker for ZXQX_resultant + +Function: _ZXQ_minpoly_worker +Class: basic +Section: programming/internals +C-Name: ZXQ_minpoly_worker +Prototype: GGGL +Help: worker for ZXQ_minpoly + +Function: _ZX_ZXY_resultant_worker +Class: basic +Section: programming/internals +C-Name: ZX_ZXY_resultant_worker +Prototype: GGGGG +Help: worker for ZX_ZXY_resultant + +Function: _ZX_composedsum_worker +Class: basic +Section: programming/internals +C-Name: ZX_composedsum_worker +Prototype: GGG +Help: worker for ZX_composedsum + +Function: _ZX_gcd_worker +Class: basic +Section: programming/internals +C-Name: ZX_gcd_worker +Prototype: GGGG +Help: worker for ZX_gcd + +Function: _ZX_resultant_worker +Class: basic +Section: programming/internals +C-Name: ZX_resultant_worker +Prototype: GGGG +Help: worker for ZX_resultant + +Function: _ZabM_inv_worker +Class: basic +Section: programming/internals +C-Name: ZabM_inv_worker +Prototype: GGG +Help: worker for ZabM_inv + +Function: _[_,] +Class: basic +Section: symbolic_operators +Help: x[y,]: y-th row of x. +Description: + (mp,small):gen $"Scalar has no rows" + (vec,small):vec rowcopy($1, $2) + (gen,small):vec rowcopy($1, $2) + +Function: _[_,_] +Class: basic +Section: symbolic_operators +Help: x[i{,j}]: i coefficient of a vector, i,j coefficient of a matrix +Description: + (mp,small):gen $"Scalar has no components" + (mp,small,small):gen $"Scalar has no components" + (vecsmall,small):small $(1)[$2] + (vecsmall,small,small):gen $"Vecsmall are single-dimensional" + (list,small):gen:copy gel(list_data($1), $2) + (vecvecsmall,small):vecsmall gel($1, $2) + (vec,small):gen:copy gel($1, $2) + (vec,small,small):gen:copy gcoeff($1, $2, $3) + (gen,small):gen:copy gel($1, $2) + (gen,small,small):gen:copy gcoeff($1, $2, $3) + +Function: _[_.._,_.._] +Class: basic +Section: symbolic_operators +C-Name: matslice0 +Prototype: GD0,L,D0,L,D0,L,D0,L, +Help: x[a..b,c..d] = [x[a,c], x[a+1,c], ...,x[b,c]; + x[a,c+1],x[a+1,c+1],...,x[b,c+1]; + ... ... ... + x[a,d], x[a+1,d] ,...,x[b,d]] + +Function: _[_.._] +Class: basic +Section: symbolic_operators +C-Name: vecslice0 +Prototype: GD0,L,L +Help: x[a..b] = [x[a],x[a+1],...,x[b]] + +Function: _\/=_ +Class: basic +Section: symbolic_operators +C-Name: gdivrounde +Prototype: &G +Help: x\/=y: shortcut for x=x\/y. +Description: + (*int, int):int:parens $1 = gdivround($1, $2) + (*pol, gen):gen:parens $1 = gdivround($1, $2) + (*gen, gen):gen:parens $1 = gdivround($1, $2) + +Function: _\/_ +Class: basic +Section: symbolic_operators +C-Name: gdivround +Prototype: GG +Help: x\/y: rounded Euclidean quotient of x and y. +Description: + (int, int):int gdivround($1, $2) + (gen, gen):gen gdivround($1, $2) + +Function: _\=_ +Class: basic +Section: symbolic_operators +C-Name: gdivente +Prototype: &G +Help: x\=y: shortcut for x=x\y. +Description: + (*small, small):small:parens $1 /= $(2) + (*int, int):int:parens $1 = gdivent($1, $2) + (*pol, gen):gen:parens $1 = gdivent($1, $2) + (*gen, gen):gen:parens $1 = gdivent($1, $2) + +Function: _\_ +Class: basic +Section: symbolic_operators +C-Name: gdivent +Prototype: GG +Help: x\y: Euclidean quotient of x and y. +Description: + (small, small):small:parens $(1)/$(2) + (int, small):int truedivis($1, $2) + (small, int):int gdiventsg($1, $2) + (int, int):int truedivii($1, $2) + (gen, small):gen gdiventgs($1, $2) + (small, gen):gen gdiventsg($1, $2) + (gen, gen):gen gdivent($1, $2) + +Function: _^_ +Class: basic +Section: symbolic_operators +C-Name: gpow +Prototype: GGp +Help: x^y: compute x to the power y. +Description: + (usmall,2):int sqru($1) + (small,2):int sqrs($1) + (int, 2):int sqri($1) + (int, 3):int powiu($1, 3) + (int, 4):int powiu($1, 4) + (int, 5):int powiu($1, 5) + (real, -1):real invr($1) + (mp, -1):mp ginv($1) + (gen, -1):gen ginv($1) + (real, 2):real sqrr($1) + (mp, 2):mp mpsqr($1) + (gen, 2):gen gsqr($1) + (int, small):gen powis($1, $2) + (real, small):real gpowgs($1, $2) + (gen, small):gen gpowgs($1, $2) + (real, int):real powgi($1, $2) + (gen, int):gen powgi($1, $2) + (gen, gen):gen:prec gpow($1, $2, $prec) + + (Fp, 2):Fp Fp_sqr($1, p) + (Fp, usmall):Fp Fp_powu($1, $2, p) + (Fp, small):Fp Fp_pows($1, $2, p) + (Fp, int):Fp Fp_pow($1, $2, p) + (FpX, 2):FpX FpX_sqr($1, p) + (FpX, usmall):FpX FpX_powu($1, $2, p) + (Fq, 2):Fq Fq_sqr($1, T, p) + (Fq, usmall):Fq Fq_powu($1, $2, T, p) + (Fq, int):Fq Fq_pow($1, $2, T, p) + (Fq, 2):Fq Fq_sqr($1, T, p) + (Fq, usmall):Fq Fq_powu($1, $2, T, p) + (Fq, int):Fq Fq_pow($1, $2, T, p) + (FqX, 2):FqX FqX_sqr($1, T, p) + (FqX, usmall):FqX FqX_powu($1, $2, T, p) + +Function: _^s +Class: basic +Section: programming/internals +C-Name: gpowgs +Prototype: GL +Help: return x^n where n is a small integer + +Function: __ +Class: basic +Section: symbolic_operators +Help: __: integral concatenation of strings. +Description: + (genstr, genstr):genstr gconcat($1, $2) + (genstr, gen):genstr gconcat($1, $2) + (gen, genstr):genstr gconcat($1, $2) + (gen, gen):genstr gconcat($genstr:1, $2) + +Function: _aprcl_step4_worker +Class: basic +Section: programming/internals +C-Name: aprcl_step4_worker +Prototype: UGGG +Help: worker for isprime (APRCL step 4) + +Function: _aprcl_step6_worker +Class: basic +Section: programming/internals +C-Name: aprcl_step6_worker +Prototype: GLGGG +Help: worker for isprime (APRCL step 6) + +Function: _avma +Class: gp2c_internal +Description: + ():pari_sp avma + +Function: _badtype +Class: gp2c_internal +Help: Code to check types. If not void, will be used as if(...). +Description: + (int):bool:parens typ($1) != t_INT + (real):bool:parens typ($1) != t_REAL + (mp):negbool is_intreal_t(typ($1)) + (vec):negbool is_matvec_t(typ($1)) + (vecsmall):bool:parens typ($1) != t_VECSMALL + (pol):bool:parens typ($1) != t_POL + (list):bool:parens typ($1) != t_LIST + (*nf):void:parens $1 = checknf($1) + (*bnf):void:parens $1 = checkbnf($1) + (bnr):void checkbnr($1) + (prid):void checkprid($1) + (clgp):void checkabgrp($1) + (ell):void checkell($1) + (*gal):void:parens $1 = checkgal($1) + +Function: _cast +Class: gp2c_internal +Help: (type1):type2 : cast expression of type1 to type2 +Description: + (void):bool 0 + (#negbool):bool ${1 value not} + (negbool):bool !$(1) + (small_int):bool + (usmall):bool + (small):bool + (lg):bool:parens $(1)!=1 + (bptr):bool *$(1) + (gen):bool !gequal0($1) + (real):bool signe($1) + (int):bool signe($1) + (mp):bool signe($1) + (pol):bool signe($1) + + (void):negbool 1 + (#bool):negbool ${1 value not} + (bool):negbool !$(1) + (lg):negbool:parens $(1)==1 + (bptr):negbool !*$(1) + (gen):negbool gequal0($1) + (int):negbool !signe($1) + (real):negbool !signe($1) + (mp):negbool !signe($1) + (pol):negbool !signe($1) + + (bool):small_int + (typ):small_int + (small):small_int + + (bool):usmall + (typ):usmall + (small):usmall + + (bool):small + (typ):small + (small_int):small + (usmall):small + (bptr):small *$(1) + (int):small itos($1) + (int):usmall itou($1) + (#lg):small:parens ${1 value 1 sub} + (lg):small:parens $(1)-1 + (gen):small gtos($1) + (gen):usmall gtou($1) + + (void):int gen_0 + (-2):int gen_m2 + (-1):int gen_m1 + (0):int gen_0 + (1):int gen_1 + (2):int gen_2 + (bool):int stoi($1) + (small):int stoi($1) + (usmall):int utoi($1) + (mp):int + (gen):int + + (mp):real + (gen):real + + (int):mp + (real):mp + (gen):mp + + (#bool):lg:parens ${1 1 value add} + (bool):lg:parens $(1)+1 + (#small):lg:parens ${1 1 value add} + (small):lg:parens $(1)+1 + + (gen):error + (gen):closure + (gen):vecsmall + + (nf):vec + (bnf):vec + (bnr):vec + (ell):vec + (clgp):vec + (prid):vec + (gal):vec + (vecvecsmall):vec + (gen):vec + + (vec):vecvecsmall + + (gen):list + + (pol):var varn($1) + (gen):var gvar($1) + + (var):pol pol_x($1) + (gen):pol + + (int):gen + (mp):gen + (vecsmall):gen + (vec):gen + (vecvecsmall):gen + (list):gen + (pol):gen + (genstr):gen + (error):gen + (closure):gen + (Fp):gen + (FpX):gen + (Fq):gen + (FqX):gen + (gen):Fp + (gen):FpX + (gen):Fq + (gen):FqX + + (gen):genstr GENtoGENstr($1) + (str):genstr strtoGENstr($1) + + (gen):str GENtostr_unquoted($1) + (genstr):str GSTR($1) + (typ):str type_name($1) + (errtyp):str numerr_name($1) + + (#str):typ ${1 str_format} + (#str):errtyp ${1 str_format} + + (bnf):nf bnf_get_nf($1) + (gen):nf + (bnr):bnf bnr_get_bnf($1) + (gen):bnf + (gen):bnr + (bnf):clgp bnf_get_clgp($1) + (bnr):clgp bnr_get_clgp($1) + (gen):clgp + (gen):ell + (gen):gal + (gen):prid + + (Fp):Fq + +Function: _cgetg +Class: gp2c_internal +Description: + (lg,#str):gen cgetg($1, ${2 str_raw}) + (gen,lg,#str):gen $1 = cgetg($2, ${3 str_raw}) + +Function: _chinese_unit_worker +Class: basic +Section: programming/internals +C-Name: chinese_unit_worker +Prototype: GGGGGG +Help: worker for _.fu + +Function: _const_expr +Class: gp2c_internal +Description: + (str):gen readseq($1) + +Function: _const_quote +Class: gp2c_internal +Description: + ("x"):var 0 + ("y"):var 1 + (str):var fetch_user_var($1) + +Function: _const_real +Class: gp2c_internal +Description: + (str):real:prec strtor($1, $prec) + +Function: _const_smallreal +Class: gp2c_internal +Description: + (0):real:prec real_0($prec) + (1):real:prec real_1($prec) + (-1):real:prec real_m1($prec) + (small):real:prec stor($1, $prec) + +Function: _decl_base +Class: gp2c_internal +Description: + (C!void) void + (C!long) long + (C!ulong) ulong + (C!int) int + (C!GEN) GEN + (C!char*) char + (C!byteptr) byteptr + (C!pari_sp) pari_sp + (C!func_GG) GEN + (C!forprime_t) forprime_t + (C!forcomposite_t) forcomposite_t + (C!forpart_t) forpart_t + (C!forperm_t) forperm_t + (C!forvec_t) forvec_t + (C!forsubset_t) forsubset_t + (C!parfor_t) parfor_t + (C!parforstep_t) parforstep_t + (C!parforeach_t) parforeach_t + (C!parforprime_t) parforprime_t + (C!parforvec_t) parforvec_t + +Function: _decl_ext +Class: gp2c_internal +Description: + (C!char*) *$1 + (C!func_GG) (*$1)(GEN, GEN) + +Function: _def_TeXstyle +Class: default +Section: default +C-Name: sd_TeXstyle +Prototype: +Help: +Doc: the bits of this default allow + \kbd{gp} to use less rigid TeX formatting commands in the logfile. This + default is only taken into account when $\kbd{log} = 3$. The bits of + \kbd{TeXstyle} have the following meaning + + 2: insert \kbd{{\bs}right} / \kbd{{\bs}left} pairs where appropriate. + + 4: insert discretionary breaks in polynomials, to enhance the probability of + a good line break. You \emph{must} then define \kbd{{\bs}PARIbreak} as + follows: + \bprog + \def\PARIbreak{\hskip 0pt plus \hsize\relax\discretionary{}{}{}} + @eprog + + The default value is \kbd{0}. + +Function: _def_breakloop +Class: default +Section: default +C-Name: sd_breakloop +Prototype: +Help: +Doc: if true, enables the ``break loop'' debugging mode, see + \secref{se:break_loop}. + + The default value is \kbd{1} if we are running an interactive \kbd{gp} + session, and \kbd{0} otherwise. + +Function: _def_colors +Class: default +Section: default +C-Name: sd_colors +Prototype: +Help: +Doc: this default is only usable if \kbd{gp} + is running within certain color-capable terminals. For instance \kbd{rxvt}, + \kbd{color\_xterm} and modern versions of \kbd{xterm} under X Windows, or + standard Linux/DOS text consoles. It causes \kbd{gp} to use a small palette of + colors for its output. With xterms, the colormap used corresponds to the + resources \kbd{Xterm*color$n$} where $n$ ranges from $0$ to $15$ (see the + file \kbd{misc/color.dft} for an example). Accepted values for this + default are strings \kbd{"$a_{1}$,\dots,$a_{k}$"} where $k\le7$ and each + $a_{i}$ is either + + \noindent\item the keyword \kbd{no} (use the default color, usually + black on transparent background) + + \noindent\item an integer between 0 and 15 corresponding to the + aforementioned colormap + + \noindent\item a triple $[c_{0},c_{1},c_{2}]$ where $c_{0}$ stands for + foreground color, $c_{1}$ for background color, and $c_{2}$ for attributes + (0 is default, 1 is bold, 4 is underline). + + The output objects thus affected are respectively error messages, + history numbers, prompt, input line, output, help messages, timer (that's + seven of them). If $k < 7$, the remaining $a_{i}$ are assumed to be \kbd{no}. + For instance + % + \bprog + default(colors, "9, 5, no, no, 4") + @eprog + \noindent + typesets error messages in color $9$, history numbers in color $5$, output in + color $4$, and does not affect the rest. + + A set of default colors for dark (reverse video or PC console) and light + backgrounds respectively is activated when \kbd{colors} is set to + \kbd{darkbg}, resp.~\kbd{lightbg} (or any proper prefix: \kbd{d} is + recognized as an abbreviation for \kbd{darkbg}). A bold variant of + \kbd{darkbg}, called \kbd{boldfg}, is provided if you find the former too + pale. + + \emacs In the present version, this default is incompatible with PariEmacs. + Changing it will just fail silently (the alternative would be to display + escape sequences as is, since Emacs will refuse to interpret them). + You must customize color highlighting from the PariEmacs side, see its + documentation. + + The default value is \kbd{""} (no colors). + +Function: _def_compatible +Class: default +Section: default +C-Name: sd_compatible +Prototype: +Obsolete: 2014-10-11 +Help: +Doc: Obsolete. This default is now a no-op. + +Function: _def_datadir +Class: default +Section: default +C-Name: sd_datadir +Prototype: +Help: +Doc: the name of directory containing the optional data files. For now, + this includes the \kbd{elldata}, \kbd{galdata}, \kbd{galpol}, \kbd{seadata} + packages. + + The default value is \kbd{/usr/local/share/pari}, or the override specified + via \kbd{Configure --datadir=}. + + \misctitle{Windows-specific note} On Windows operating systems, the + special value \kbd{@} stands for ``the directory where the \kbd{gp} + binary is installed''. This is the default value. + +Function: _def_debug +Class: default +Section: default +C-Name: sd_debug +Prototype: +Help: +Doc: debugging level. If it is nonzero, some extra messages may be printed, + according to what is going on (see~\b{g}). To turn on and off diagnostics + attached to a specific feature (such as the LLL algorithm), use + \tet{setdebug}. + + The default value is \kbd{0} (no debugging messages). + +Function: _def_debugfiles +Class: default +Section: default +C-Name: sd_debugfiles +Prototype: +Obsolete: 2021-06-14 +Help: +Doc: This is a deprecated alias for \kbd{setdebug("io",)}. If nonzero, + \kbd{gp} will print information on file descriptors in use and I/O + operations (see~\b{gf}). + + The default value is \kbd{0} (no debugging messages). + +Function: _def_debugmem +Class: default +Section: default +C-Name: sd_debugmem +Prototype: +Help: +Doc: memory debugging level (see \b{gm}). If this is nonzero, \kbd{gp} will + print increasingly precise notifications about memory use: + + \item $\kbd{debugmem} > 0$, notify when \kbd{parisize} changes (within the + boundaries set by \kbd{parisizemax}); + + \item $\kbd{debugmem} > 1$, indicate any important garbage collection and the + function it is taking place in; + + \item $\kbd{debugmem} > 2$, indicate the creation/destruction of + ``blocks'' (or clones); expect lots of messages. + + \noindent {\bf Important Note:} + if you are running a version compiled for debugging (see Appendix~A) and + $\kbd{debugmem} > 1$, \kbd{gp} will further regularly print information on + memory usage, notifying whenever stack usage goes up or down by 1 MByte. + This functionality is disabled on non-debugging builds as it noticeably + slows down the performance. + + The default value is \kbd{1}. + +Function: _def_echo +Class: default +Section: default +C-Name: sd_echo +Prototype: +Help: +Doc: this default can be 0 (off), 1 (on) or 2 (on, raw). When \kbd{echo} + mode is on, each command is reprinted before being executed. This can be + useful when reading a file with the \b{r} or \kbd{read} commands. For + example, it is turned on at the beginning of the test files used to check + whether \kbd{gp} has been built correctly (see \b{e}). When \kbd{echo} is set + to 1 the input is cleaned up, removing white space and comments and uniting + multi-line input. When set to 2 (raw), the input is written as-is, without any + pre-processing. + + The default value is \kbd{0} (no echo). + +Function: _def_factor_add_primes +Class: default +Section: default +C-Name: sd_factor_add_primes +Prototype: +Help: +Doc: this toggle is either 1 (on) or 0 (off). If on, + the integer factorization machinery calls \tet{addprimes} on prime + factors that were difficult to find (larger than $2^{24}$), so they are + automatically tried first in other factorizations. If a routine is performing + (or has performed) a factorization and is interrupted by an error or via + Control-C, this lets you recover the prime factors already found. The + downside is that a huge \kbd{addprimes} table unrelated to the current + computations will slow down arithmetic functions relying on integer + factorization; one should then empty the table using \tet{removeprimes}. + + The default value is \kbd{0}. + +Function: _def_factor_proven +Class: default +Section: default +C-Name: sd_factor_proven +Prototype: +Help: +Doc: this toggle is either 1 (on) or 0 (off). By + default, the factors output by the integer factorization machinery are + only pseudo-primes, not proven primes. If this toggle is + set, a primality proof is done for each factor and all results depending on + integer factorization are fully proven. This flag does not affect partial + factorization when it is explicitly requested. It also does not affect the + private table managed by \tet{addprimes}: its entries are included as is in + factorizations, without being tested for primality. + + The default value is \kbd{0}. + +Function: _def_factorlimit +Class: default +Section: default +C-Name: sd_factorlimit +Prototype: +Help: +Doc: \kbd{gp} precomputes a list of + all primes less than \kbd{primelimit} at initialization time (and can quickly + generate more primes on demand, up to the square of that bound). Let $N$ + be an integer. The command \kbd{factor}$(N)$ factors the integer, starting + by trial division by all primes up to some bound (which depends on the size + of $N$ and less than $2^{19}$ is any case), then moving on to more advanced + algorithms. When additionally $D$ is an integer, \kbd{factor}$(N, D)$ uses + \emph{only} trial division by primes less than $D$. In both case, trial + division is sped up by precomputations involving primes up to another bound + called \kbd{factorlimit}. Trial division up to a larger bound is possible, + but will be slower than for bounds lower than \kbd{factorlimit} and will + slow down factorization on average. If \kbd{factorlimit} is larger than + \kbd{primelimit}, then \kbd{primelimit} is increased to match + \kbd{factorlimit}. + + In the present version, precomputations are only used on startup and + changing either \kbd{primelimit} or \kbd{factorlimit} will not recompute + new tables. Changing \kbd{primelimit} has no effect, while changing + \kbd{factorlimit} affects the behavior in factorizations. + + The default value is $2^{20}$, which is the default \kbd{primelimit}. + This default is only used on startup: changing it will not recompute a new + table. + + Note that the precomputations are expensive both in terms of time and space, + although softly linear in the bound, and the ones attached to + \kbd{factorlimit} more so. So neither should be taken too large. Here are + sample timings: in the first column are the increasing + values of \kbd{primelimit}, in the second column is the startup time + keeping \kbd{factorlimit} at its default value, and the third column + is the startup time with $\kbd{factorlimit} = \kbd{primelimit}$. + \bprog + 2^20: 40 ms 40 ms + 2^23: 40 ms 230 ms + 2^26: 140 ms 2,410 ms + 2^29: 810 ms 27,240 ms + 2^32: 6,040 ms 293,660 ms + @eprog\noindent The final $2^{32}$ for \kbd{factorlimit} requires a 10GB + stack. On the other hand, + here are timings trying \kbd{factor}$(p, D)$ for some random $1000$-bit prime + (so we are in the worst case of performing trial division in a setting where + it cannot succeed) + and increasing values of $D$. We use a \kbd{primelimit} of $2^{32}$; + the first column corresponds to the values of $D$, the second to the times for + the default \kbd{factorlimit} and the third to fifth for \kbd{factorlimit} + matching $D$, $D/2$ and $D/4$ respectively. + \bprog + 2^20: 1 ms 1 ms 6 ms 18 ms + 2^23: 72 ms 18 ms 21 ms 63 ms + 2^26: 296 ms 50 ms 176 ms 233 ms + 2^29: 1,911 ms 266 ms 1,023 ms 1,404 ms + 2^32: 15,505 ms 2,406 ms 6,954 ms 15,264 ms + @eprog\noindent As expected, matching \kbd{factorlimit}'s fast trial + division to the desired trial division bound $D$ is optimal if we do not + take precomputation time into account. But this data + also shows that if you need to often trial divide above 4 \kbd{factorlimit}, + then you should not bother and can just as well stick with the default value: + the extra efficiency up to \kbd{factorlimit} is negligible compared to the + naive trial division that will follow. Whereas the increase in memory usage + and startup time are \emph{very} noticeable. + + The default value is $2^{20}$. + +Function: _def_format +Class: default +Section: default +C-Name: sd_format +Prototype: +Help: +Doc: of the form x$.n$, where x (conversion style) + is a letter in $\{\kbd{e},\kbd{f},\kbd{g}\}$, and $n$ (precision) is an + integer; this affects the way real numbers are printed: + + \item If the conversion style is \kbd{e}, real numbers are printed in + \idx{scientific format}, always with an explicit exponent, + e.g.~\kbd{3.3 E-5}. + + \item In style \kbd{f}, real numbers are generally printed in + \idx{fixed floating point format} without exponent, e.g.~\kbd{0.000033}. A + large real number, whose integer part is not well defined (not enough + significant digits), is printed in style~\kbd{e}. For instance + \kbd{10.\pow 100} known to ten significant digits is always printed in style + \kbd{e}. + + \item In style \kbd{g}, nonzero real numbers are printed in \kbd{f} format, + except when their decimal exponent is $< -4$, in which case they are printed + in \kbd{e} format. Real zeroes (of arbitrary exponent) are printed in \kbd{e} + format. + + The precision $n$ is the number of significant digits printed for real + numbers, except if $n<0$ where all the significant digits will be printed + (initial default is 38 decimal digits). For more powerful formatting + possibilities, see \tet{printf} and \tet{strprintf}. + + The default value is \kbd{"g.38"}. + +Function: _def_graphcolormap +Class: default +Section: default +C-Name: sd_graphcolormap +Prototype: +Help: +Doc: a vector of colors, to be used by hi-res graphing routines. Its length is + arbitrary, but it must contain at least 3 entries: the first 3 colors are + used for background, frame/ticks and axes respectively. All colors in the + colormap may be freely used in \tet{plotcolor} calls. + + A color is either given as in the default by character strings or by an RGB + code. For valid color names, see the standard \kbd{rgb.txt} file in X11 + distributions, where we restrict to lowercase letters and remove all + whitespace from color names. An RGB code is a vector with 3 integer entries + between 0 and 255 or a \kbd{\#} followed by 6 hexadecimal digits. + For instance \kbd{[250, 235, 215]}, \kbd{"\#faebd7"} and + \kbd{"antiquewhite"} all represent the same color. + + The default value is [\kbd{"white"}, \kbd{"black"}, \kbd{"blue"}, + \kbd{"violetred"}, \kbd{"red"}, \kbd{"green"}, \kbd{"grey"}, + \kbd{"gainsboro"}]. + + The colormap elements can not be changed individually as in a vector (you must + either leave the colormap alone or change it globally). All color functions + allow you either to hardcode a color given its descriptive name or RGB code, + or to use a relative color scheme by changing the colormap and referring to an + index in that table: for historical and compatibility reasons, + the indexing is $0$-based (as in C) and not $1$-based as would be expected in + a GP vector. This means that the index~$0$ in the default colormap represents + \kbd{"white"}, $1$ is \kbd{"black"}, and so on. + +Function: _def_graphcolors +Class: default +Section: default +C-Name: sd_graphcolors +Prototype: +Help: +Doc: entries in the + \tet{graphcolormap} that will be used to plot multi-curves. The successive + curves are drawn in colors whose index in \kbd{graphcolormap} are the + non-negative integers + + \kbd{graphcolors[1]}, \kbd{graphcolors[2]}, \dots + + cycling when the \kbd{graphcolors} list is exhausted. Beware that for + historical and compatibility reasons, \kbd{graphcolormap} is $0$-based. + + The default value is \kbd{[4,5]}. With factory settings for + \kbd{graphcolormap}, this corresponds to \kbd{"red"} then \kbd{"green"}. + +Function: _def_help +Class: default +Section: default +C-Name: sd_help +Prototype: +Help: +Doc: name of the external help program to use from within \kbd{gp} when + extended help is invoked, usually through a \kbd{??} or \kbd{???} request + (see \secref{se:exthelp}), or \kbd{M-H} under readline (see + \secref{se:readline}). + + \misctitle{Windows-specific note} On Windows operating systems, if the + first character of \kbd{help} is \kbd{@}, it is replaced by ``the directory + where the \kbd{gp} binary is installed''. + + The default value is the path to the \kbd{gphelp} script we install. + +Function: _def_histfile +Class: default +Section: default +C-Name: sd_histfile +Prototype: +Help: +Doc: name of a file where + \kbd{gp} will keep a history of all \emph{input} commands (results are + omitted). If this file exists when the value of \kbd{histfile} changes, + it is read in and becomes part of the session history. Thus, setting this + default in your gprc saves your readline history between sessions. Setting + this default to the empty string \kbd{""} changes it to + \kbd{$<$undefined$>$}. Note that, by default, the number of history entries + saved is not limited: set \kbd{history-size} in readline's \kbd{.inputrc} + to limit the file size. + + The default value is \kbd{$<$undefined$>$} (no history file). + +Function: _def_histsize +Class: default +Section: default +C-Name: sd_histsize +Prototype: +Help: +Doc: \kbd{gp} keeps a history of the last + \kbd{histsize} results computed so far, which you can recover using the + \kbd{\%} notation (see \secref{se:history}). When this number is exceeded, + the oldest values are erased. Tampering with this default is the only way to + get rid of the ones you do not need anymore. + + The default value is \kbd{5000}. + +Function: _def_lines +Class: default +Section: default +C-Name: sd_lines +Prototype: +Help: +Doc: if set to a positive value, \kbd{gp} prints at + most that many lines from each result, terminating the last line shown with + \kbd{[+++]} if further material has been suppressed. The various \kbd{print} + commands (see \secref{se:gp_program}) are unaffected, so you can always type + \kbd{print(\%)} or \b{a} to view the full result. If the actual screen width + cannot be determined, a ``line'' is assumed to be 80 characters long. + + The default value is \kbd{0}. + +Function: _def_linewrap +Class: default +Section: default +C-Name: sd_linewrap +Prototype: +Help: +Doc: if set to a positive value, \kbd{gp} wraps every single line after + printing that many characters. + + The default value is \kbd{0} (unset). + +Function: _def_log +Class: default +Section: default +C-Name: sd_log +Prototype: +Help: +Doc: this can be either 0 (off) or 1, 2, 3 + (on, see below for the various modes). When logging mode is turned on, \kbd{gp} + opens a log file, whose exact name is determined by the \kbd{logfile} + default. Subsequently, all the commands and results will be written to that + file (see \b{l}). In case a file with this precise name already existed, it + will not be erased: your data will be \emph{appended} at the end. + + The specific positive values of \kbd{log} have the following meaning + + 1: plain logfile + + 2: emit color codes to the logfile (if \kbd{colors} is set). + + 3: write LaTeX output to the logfile (can be further customized using + \tet{TeXstyle}). + + The default value is \kbd{0}. + + \misctitle{Note} Logging starts as soon as \kbd{log} is set to a nonzero + value. In particular, when \kbd{log} is set in \kbd{gprc}, warnings and + errors triggered from the rest of the file will be written in the logfile. + For instance, on clean startup, the logfile will start by \kbd{Done.} + (from the \kbd{Reading GPRC:\dots Done.} diagnostic printed when starting + \kbd{gp}), then the \kbd{gp} header and prompt. + +Function: _def_logfile +Class: default +Section: default +C-Name: sd_logfile +Prototype: +Help: +Doc: name of the log file to be used when the \kbd{log} toggle is on. + Environment and time expansion are performed. + + The default value is \kbd{"pari.log"}. + +Function: _def_nbthreads +Class: default +Section: default +C-Name: sd_nbthreads +Prototype: +Help: +Doc: This default is specific to the \emph{parallel} version of PARI and gp + (built via \kbd{Configure --mt=pthread} or \kbd{mpi}) and is ignored + otherwise. In parallel mode, it governs the number of threads to use for + parallel computing. The exact meaning and default value depend on the + \kbd{mt} engine used: + + \item \kbd{single}: not used (always a single thread). + + \item \kbd{pthread}: number of threads (unlimited, default: number of cores) + + \item \kbd{mpi}: number of MPI processes to use (limited to the number + allocated by \kbd{mpirun}, default: use all allocated processes). + + See also \kbd{threadsize} and \kbd{threadsizemax}. + +Function: _def_new_galois_format +Class: default +Section: default +C-Name: sd_new_galois_format +Prototype: +Help: +Doc: this toggle is either 1 (on) or 0 (off). If on, + the \tet{polgalois} command will use a different, more + consistent, naming scheme for Galois groups. This default is provided to + ensure that scripts can control this behavior and do not break unexpectedly. + + The default value is \kbd{0}. This value will change to $1$ (set) in the next + major version. + +Function: _def_output +Class: default +Section: default +C-Name: sd_output +Prototype: +Help: +Doc: there are three possible values: 0 + (=~\var{raw}), 1 (=~\var{prettymatrix}), or 3 + (=~\var{external} \var{prettyprint}). This + means that, independently of the default \kbd{format} for reals which we + explained above, you can print results in three ways: + + \item \tev{raw format}, i.e.~a format which is equivalent to what you + input, including explicit multiplication signs, and everything typed on a + line instead of two dimensional boxes. This can have several advantages, for + instance it allows you to pick the result with a mouse or an editor, and to + paste it somewhere else. + + \item \tev{prettymatrix format}: this is identical to raw format, except + that matrices are printed as boxes instead of horizontally. This is + prettier, but takes more space and cannot be used for input. Column vectors + are still printed horizontally. + + \item \tev{external prettyprint}: pipes all \kbd{gp} + output in TeX format to an external prettyprinter, according to the value of + \tet{prettyprinter}. The default script (\tet{tex2mail}) converts its input + to readable two-dimensional text. + + Independently of the setting of this default, an object can be printed + in any of the three formats at any time using the commands \b{a} and \b{m} + and \b{B} respectively. + + The default value is \kbd{1} (\var{prettymatrix}). + +Function: _def_parisize +Class: default +Section: default +C-Name: sd_parisize +Prototype: +Help: +Doc: \kbd{gp}, and in fact any program using the PARI + library, needs a \tev{stack} in which to do its computations; \kbd{parisize} + is the stack size, in bytes. It is recommended to increase this + default using a \tet{gprc}, to the value you believe PARI should be happy + with, given your typical computation. We strongly recommend to also + set \tet{parisizemax} to a much larger value in your \kbd{gprc}, about what + you believe your machine can stand: PARI will then try to fit its + computations within about \kbd{parisize} bytes, but will increase the stack + size if needed (up to \kbd{parisizemax}). PARI will restore the stack size + to the originally requested \kbd{parisize} once we get back to the user's + prompt. + + If \tet{parisizemax} is unset, this command has a very unintuitive behaviour + since it must abort pending operations, see \kbd{??allocatemem}. + + The default value is 8M. + +Function: _def_parisizemax +Class: default +Section: default +C-Name: sd_parisizemax +Prototype: +Help: +Doc: \kbd{gp}, and in fact any program using the PARI library, needs a + \tev{stack} in which to do its computations. If nonzero, \tet{parisizemax} + is the maximum size the stack can grow to, in bytes. If zero, the stack will + not automatically grow, and will be limited to the value of \kbd{parisize}. + + When \kbd{parisizemax} is set, PARI tries to fit its + computations within about \kbd{parisize} bytes, but will increase the stack + size if needed, roughly doubling it each time (up to \kbd{parisizemax} + of course!) and printing a message such as \kbd{Warning: increasing stack size to} + \var{some value}. Once the memory intensive computation is over, PARI + will restore the stack size to the originally requested \kbd{parisize} + without printing further messages. + + We \emph{strongly} recommend to set \tet{parisizemax} permanently to a large + nonzero value in your \tet{gprc}, about what you believe your machine can + stand. It is possible to increase or decrease \kbd{parisizemax} inside a + running \kbd{gp} session, just use \kbd{default} as usual. + + The default value is $0$, for backward compatibility reasons. + +Function: _def_path +Class: default +Section: default +C-Name: sd_path +Prototype: +Help: +Doc: this is a list of directories, separated by colons ':' + (semicolons ';' in the DOS world, since colons are preempted for drive names). + When asked to read a file whose name is not given by an absolute path + (does not start with \kbd{/}, \kbd{./} or \kbd{../}), \kbd{gp} will look for + it in these directories, in the order they were written in \kbd{path}. Here, + as usual, \kbd{.} means the current directory, and \kbd{..} its immediate + parent. Environment expansion is performed. + + The default value is \kbd{".:\til:\til/gp"} on UNIX systems, + \kbd{".;C:\bs;C:\bs GP"} on DOS, OS/2 and Windows, and \kbd{"."} otherwise. + +Function: _def_plothsizes +Class: default +Section: default +C-Name: sd_plothsizes +Prototype: +Help: +Doc: if the graphic driver allows it, the array contains the size of the + terminal, the size of the font, the size of the ticks. + +Function: _def_prettyprinter +Class: default +Section: default +C-Name: sd_prettyprinter +Prototype: +Help: +Doc: the name of an external prettyprinter to use when + \kbd{output} is~3 (alternate prettyprinter). Note that the default + \tet{tex2mail} looks much nicer than the built-in ``beautified + format'' ($\kbd{output} = 2$). + + The default value is \kbd{"tex2mail -TeX -noindent -ragged -by\_par"}. + +Function: _def_primelimit +Class: default +Section: default +C-Name: sd_primelimit +Prototype: +Help: +Doc: \kbd{gp} precomputes a list of + all primes less than \kbd{primelimit} at initialization time, and can build + fast sieves on demand to quickly iterate over primes up to the \emph{square} + of \kbd{primelimit}. These are used by functions looping over consecutive + small primes. A related default is \kbd{factorlimit}, setting an upper + bound for the small primes that can be quickly detected through fast trial + division; you can still trial divide far above \kbd{factorlimit}, through + $\kbd{factor}(N, B)$ with large $B$ but a slow algorithm will be used + above \kbd{factorlimit}. If \kbd{primelimit} is set to a lower value than + \kbd{factorlimit}, it is silently increased to match \kbd{factorlimit}. + + The default value is $2^{20}$. Since almost all arithmetic functions + eventually require some table of prime numbers, PARI guarantees that the + first 6547 primes, up to and including $65557 = 2^{16} + 21$, are precomputed, + even if \kbd{primelimit} is $1$. + + A value of $2^{32}$ allows to quickly iterate over consecutive primes up + to $2^{64}$, and is + the upper range of what is generally useful. (Allow for a startup time of + about 6 seconds.) On the other hand, \kbd{factorlimit} is more expensive: it + must build a product tree of all primes up to the bound, which can + considerably increase startup time. A \kbd{factorlimit} of $2^{32}$ will + increase startup time to about 5 minutes; and is only useful if you + intend to call \kbd{factor}$(N, D)$ \emph{many} times with values of $D$ about + $2^{32}$ or $2^{33}$. + + This default is only used on startup: changing it will not recompute a new + table. Here are sample timings for startup using increasing + values of \kbd{primelimit}: + \bprog + 2^20: 40 ms + 2^23: 230 ms + 2^26: 2,410 ms + 2^29: 27,240 ms + 2^32: 293,660 ms + @eprog + + \misctitle{Deprecated feature} \kbd{factorlimit} was used in some + situations by algebraic number theory functions using the + \tet{nf_PARTIALFACT} flag (\tet{nfbasis}, \tet{nfdisc}, \tet{nfinit}, \dots): + this assumes that all primes $p > \kbd{factorlimit}$ have a certain + property (the equation order is $p$-maximal). This is never done by default, + and must be explicitly set by the user of such functions. Nevertheless, + these functions now provide a more flexible interface, and their use + of the global default \kbd{factorlimit} is deprecated. + + \misctitle{Deprecated feature} \kbd{factor(N, 0)} is used to partially + factor integers by removing all prime factors $\leq$ \kbd{factorlimit}. + Don't use this, supply an explicit bound: \kbd{factor(N, bound)}, + which avoids relying on an unpredictable global variable. + + The default value is $2^{20} = 1048576$. + +Function: _def_prompt +Class: default +Section: default +C-Name: sd_prompt +Prototype: +Help: +Doc: a string that will be printed as + prompt. Note that most usual escape sequences are available there: \b{e} for + Esc, \b{n} for Newline, \dots, \kbd{\bs\bs} for \kbd{\bs}. Time expansion is + performed. + + This string is sent through the library function \tet{strftime} (on a + Unix system, you can try \kbd{man strftime} at your shell prompt). This means + that \kbd{\%} constructs have a special meaning, usually related to the time + and date. For instance, \kbd{\%H} = hour (24-hour clock) and \kbd{\%M} = + minute [00,59] (use \kbd{\%\%} to get a real \kbd{\%}). + + If you use \kbd{readline}, escape sequences in your prompt will result in + display bugs. If you have a relatively recent \kbd{readline} (see the comment + at the end of \secref{se:def,colors}), you can brace them with special sequences + (\kbd{\bs[} and \kbd{\bs]}), and you will be safe. If these just result in + extra spaces in your prompt, then you'll have to get a more recent + \kbd{readline}. See the file \kbd{misc/gprc.dft} for an example. + + \emacs {\bf Caution}: PariEmacs needs to know about the prompt pattern to + separate your input from previous \kbd{gp} results, without ambiguity. It is + not a trivial problem to adapt automatically this regular expression to an + arbitrary prompt (which can be self-modifying!). See PariEmacs's + documentation. + + The default value is \kbd{"? "}. + +Function: _def_prompt_cont +Class: default +Section: default +C-Name: sd_prompt_cont +Prototype: +Help: +Doc: a string that will be printed + to prompt for continuation lines (e.g. in between braces, or after a + line-terminating backslash). Everything that applies to \kbd{prompt} + applies to \kbd{prompt\_cont} as well. + + The default value is \kbd{""}. + +Function: _def_psfile +Class: default +Section: default +C-Name: sd_psfile +Prototype: +Obsolete: 2018-02-01 +Help: +Doc: This default is obsolete, use one of plotexport, plothexport or + plothrawexport functions and write the result to file. + +Function: _def_readline +Class: default +Section: default +C-Name: sd_readline +Prototype: +Help: +Doc: switches readline line-editing + facilities on and off. This may be useful if you are running \kbd{gp} in a Sun + \tet{cmdtool}, which interacts badly with readline. Of course, until readline + is switched on again, advanced editing features like automatic completion + and editing history are not available. + + The default value is \kbd{1}. + +Function: _def_realbitprecision +Class: default +Section: default +C-Name: sd_realbitprecision +Prototype: +Help: +Doc: the number of significant bits used to convert exact inputs given to + transcendental functions (see \secref{se:trans}), or to create + absolute floating point constants (input as \kbd{1.0} or \kbd{Pi} for + instance). Unless you tamper with the \tet{format} default, this is also + the number of significant bits used to print a \typ{REAL} number; + \kbd{format} will override this latter behavior, and allow you to have a + large internal precision while outputting few digits for instance. + + Note that most PARI's functions currently handle precision on a word basis (by + increments of 32 or 64 bits), hence bit precision may be a little larger + than the number of bits you expected. For instance to get 10 bits of + precision, you need one word of precision which, on a 64-bit machine, + correspond to 64 bits. To make things even more confusing, this internal bit + accuracy is converted to decimal digits when printing floating point numbers: + now 64 bits correspond to 19 printed decimal digits + ($19 < \log_{10}(2^{64}) < 20$). + + The value returned when typing \kbd{default(realbitprecision)} is the internal + number of significant bits, not the number of printed decimal digits: + \bprog + ? default(realbitprecision, 10) + ? \pb + realbitprecision = 64 significant bits + ? default(realbitprecision) + %1 = 64 + ? \p + realprecision = 3 significant digits + ? default(realprecision) + %2 = 19 + @eprog\noindent Note that \tet{realprecision} and \kbd{\bs p} allow + to view and manipulate the internal precision in decimal digits. + + The default value is \kbd{128} bits. + +Function: _def_realprecision +Class: default +Section: default +C-Name: sd_realprecision +Prototype: +Help: +Doc: the number of significant digits used to convert exact inputs given to + transcendental functions (see \secref{se:trans}), or to create + absolute floating point constants (input as \kbd{1.0} or \kbd{Pi} for + instance). Unless you tamper with the \tet{format} default, this is also + the number of significant digits used to print a \typ{REAL} number; + \kbd{format} will override this latter behavior, and allow you to have a + large internal precision while outputting few digits for instance. + + Note that PARI's internal precision works on a word basis (by increments of + 32 or 64 bits), hence may be a little larger than the number of decimal + digits you expected. For instance to get 2 decimal digits you need one word + of precision which, on a 64-bit machine, actually gives you 19 digits ($19 < + \log_{10}(2^{64}) < 20$). The value returned when typing + \kbd{default(realprecision)} is the internal number of significant digits, + not the number of printed digits: + \bprog + ? default(realprecision, 2) + realprecision = 19 significant digits (2 digits displayed) + ? default(realprecision) + %1 = 19 + @eprog + The default value is \kbd{38} decimal digits. + +Function: _def_recover +Class: default +Section: default +C-Name: sd_recover +Prototype: +Help: +Doc: this toggle is either 1 (on) or 0 (off). If you change this to $0$, any + error becomes fatal and causes the gp interpreter to exit immediately. Can be + useful in batch job scripts. + + The default value is \kbd{1}. + +Function: _def_secure +Class: default +Section: default +C-Name: sd_secure +Prototype: +Help: +Doc: this toggle is either 1 (on) or 0 (off). If on, the \tet{system} and + \tet{extern} command are disabled. These two commands are potentially + dangerous when you execute foreign scripts since they let \kbd{gp} execute + arbitrary UNIX commands. \kbd{gp} will ask for confirmation before letting + you (or a script) unset this toggle. + + The default value is \kbd{0}. + +Function: _def_seriesprecision +Class: default +Section: default +C-Name: sd_seriesprecision +Prototype: +Help: +Doc: number of significant terms + when converting a polynomial or rational function to a power series + (see~\b{ps}). + + The default value is \kbd{16}. + +Function: _def_simplify +Class: default +Section: default +C-Name: sd_simplify +Prototype: +Help: +Doc: this toggle is either 1 (on) or 0 (off). When the PARI library computes + something, the type of the + result is not always the simplest possible. The only type conversions which + the PARI library does automatically are rational numbers to integers (when + they are of type \typ{FRAC} and equal to integers), and similarly rational + functions to polynomials (when they are of type \typ{RFRAC} and equal to + polynomials). This feature is useful in many cases, and saves time, but can + be annoying at times. Hence you can disable this and, whenever you feel like + it, use the function \kbd{simplify} (see Chapter 3) which allows you to + simplify objects to the simplest possible types recursively (see~\b{y}). + \sidx{automatic simplification} + + The default value is \kbd{1}. + +Function: _def_sopath +Class: default +Section: default +C-Name: sd_sopath +Prototype: +Help: +Doc: this is a list of directories, separated by colons ':' + (semicolons ';' in the DOS world, since colons are preempted for drive names). + When asked to \tet{install} an external symbol from a shared library whose + name is not given by an absolute path (does not start with \kbd{/}, \kbd{./} + or \kbd{../}), \kbd{gp} will look for it in these directories, in the order + they were written in \kbd{sopath}. Here, as usual, \kbd{.} means the current + directory, and \kbd{..} its immediate parent. Environment expansion is + performed. + + The default value is \kbd{""}, corresponding to an empty list of + directories: \tet{install} will use the library name as input (and look in + the current directory if the name is not an absolute path). + +Function: _def_strictargs +Class: default +Section: default +C-Name: sd_strictargs +Prototype: +Help: +Doc: this toggle is either 1 (on) or 0 (off). If on, all arguments to \emph{new} + user functions are mandatory unless the function supplies an explicit default + value. + Otherwise arguments have the default value $0$. + + In this example, + \bprog + fun(a,b=2)=a+b + @eprog + \kbd{a} is mandatory, while \kbd{b} is optional. If \kbd{strictargs} is on: + \bprog + ? fun() + *** at top-level: fun() + *** ^----- + *** in function fun: a,b=2 + *** ^----- + *** missing mandatory argument 'a' in user function. + @eprog + This applies to functions defined while \kbd{strictargs} is on. Changing \kbd{strictargs} + does not affect the behavior of previously defined functions. + + The default value is \kbd{0}. + +Function: _def_strictmatch +Class: default +Section: default +C-Name: sd_strictmatch +Prototype: +Obsolete: 2014-10-11 +Help: +Doc: Obsolete. This toggle is now a no-op. + +Function: _def_threadsize +Class: default +Section: default +C-Name: sd_threadsize +Prototype: +Help: +Doc: This default is specific to the \emph{parallel} version of PARI and gp + (built via \kbd{Configure --mt=pthread} or \kbd{mpi}) and is ignored + otherwise. In parallel mode, + each thread allocates its own private \tev{stack} for its + computations, see \kbd{parisize}. This value determines the size in bytes of + the stacks of each thread, so the total memory allocated will be + $\kbd{parisize}+\kbd{nbthreads}\times\kbd{threadsize}$. + + If set to $0$, the value used is the same as \kbd{parisize}. It is not + easy to estimate reliably a sufficient value for this parameter because PARI + itself will parallelize computations and we recommend to not set this value + explicitly unless it solves a specific problem for you. For instance if you + see frequent messages of the form + \bprog + *** Warning: not enough memory, new thread stack 10000002048 + @eprog (Meaning that \kbd{threadsize} had to be temporarily increased.) + On the other hand we strongly recommend to set \kbd{parisizemax} and + \kbd{threadsizemax} to a nonzero value. + + The default value is $0$. + +Function: _def_threadsizemax +Class: default +Section: default +C-Name: sd_threadsizemax +Prototype: +Help: +Doc: This default is specific to the \emph{parallel} version of PARI and gp + (built via \kbd{Configure --mt=pthread} or \kbd{mpi}) and is ignored + otherwise. In parallel mode, + each threads allocates its own private \tev{stack} for + its computations, see \kbd{parisize} and \kbd{parisizemax}. The + values of \kbd{threadsize} and \kbd{threadsizemax} determine the usual + and maximal size in bytes of the stacks of each thread, so the total memory + allocated will + be between $\kbd{parisize}+\kbd{nbthreads}\times\kbd{threadsize}$. and + $\kbd{parisizemax}+\kbd{nbthreads}\times\kbd{threadsizemax}$. + + If set to $0$, the value used is the same as \kbd{threadsize}. We strongy + recommend to set both \kbd{parisizemax} and \kbd{threadsizemax} to a + nonzero value. + + The default value is $0$. + +Function: _def_timer +Class: default +Section: default +C-Name: sd_timer +Prototype: +Help: +Doc: this toggle is either 1 (on) or 0 (off). Every instruction sequence + in the gp calculator (anything ended by a newline in your input) is timed, + to some accuracy depending on the hardware and operating system. When + \tet{timer} is on, each such timing is printed immediately before the + output as follows: + \bprog + ? factor(2^2^7+1) + time = 108 ms. \\ this line omitted if 'timer' is 0 + %1 = + [ 59649589127497217 1] + + [5704689200685129054721 1] + @eprog\noindent (See also \kbd{\#} and \kbd{\#\#}.) + + The time measured is the user \idx{CPU time}, not including the time + for printing the results. If the time is negligible ($< 1$ ms.), nothing is + printed: in particular, no timing should be printed when defining a user + function or an alias, or installing a symbol from the library. + + If you are using a parallel version of \kbd{gp}, the output is more + complex, such as + \bprog + ? isprime( 10^300 + 331 ) + cpu time = 3,206 ms, real time = 1,289 ms. \\ omitted if 'timer' is 0 + %1 = 1 + @eprog\noindent Now, \kbd{real time} is the wallclock time, and \kbd{cpu time} + is the sum of the CPU times spent by the different threads. + + The default value is \kbd{0} (off). + +Function: _default_check +Class: gp2c_internal +Help: Code to check for the default marker +Description: + (C!GEN):bool !$(1) + (var):bool $(1) == -1 + +Function: _default_marker +Class: gp2c_internal +Help: Code for default value of GP function +Description: + (C!GEN) NULL + (var) -1 + (small) 0 + (str) "" + +Function: _derivfun +Class: basic +Section: programming/internals +C-Name: derivfun0 +Prototype: GGGD1,L,p +Help: _derivfun(args,def,closure,k) numerical kth-derivation of closure with respect to + the first variable at args + +Function: _diffptr +Class: gp2c_internal +Help: Table of difference of primes. +Description: + ():bptr diffptr + +Function: _dirartin_worker +Class: basic +Section: programming/internals +C-Name: dirartin_worker +Prototype: GUGGGG +Help: lfunartin worker + +Function: _direllnf_worker +Class: basic +Section: programming/internals +C-Name: direllnf_worker +Prototype: GUG +Help: ellan worker + +Function: _direllsympow_worker +Class: basic +Section: programming/internals +C-Name: direllsympow_worker +Prototype: GUGU +Help: lfunsympow worker + +Function: _dirgenus2_worker +Class: basic +Section: programming/internals +C-Name: dirgenus2_worker +Prototype: GLG +Help: lfungenus2 worker + +Function: _dirhgm_worker +Class: basic +Section: programming/internals +C-Name: dirhgm_worker +Prototype: GUGG +Help: worker for hgmcoefs + +Function: _ecpp_ispsp_worker +Class: basic +Section: programming/internals +C-Name: ecpp_ispsp_worker +Prototype: G +Help: worker for isprime (ECPP ispseudoprime step) + +Function: _ecpp_sqrt_worker +Class: basic +Section: programming/internals +C-Name: ecpp_sqrt_worker +Prototype: GGG +Help: worker for isprime (ECPP sqrt step) + +Function: _ecpp_step2_worker +Class: basic +Section: programming/internals +C-Name: ecpp_step2_worker +Prototype: GGGL +Help: worker for isprime (step 2) + +Function: _eisker_worker +Class: basic +Section: programming/internals +C-Name: eisker_worker +Prototype: GGGGG +Help: worker for eisker + +Function: _ellQ_factorback_worker +Class: basic +Section: programming/internals +C-Name: ellQ_factorback_worker +Prototype: GGGGU +Help: worker for ellQ_factorback + +Function: _err_primes +Class: gp2c_internal +Description: + ():void pari_err(e_MAXPRIME) + +Function: _err_type +Class: gp2c_internal +Description: + (str,gen):void pari_err_TYPE($1,$2) + +Function: _eval_mnemonic +Class: basic +Section: programming/internals +C-Name: eval_mnemonic +Prototype: lGs +Help: Convert a mnemonic string to a flag. + +Function: _factor_Aurifeuille +Class: basic +Section: programming/internals +C-Name: factor_Aurifeuille +Prototype: GL +Help: _factor_Aurifeuille(a,d): return an algebraic factor of Phi_d(a), a != 0 + +Function: _factor_Aurifeuille_prime +Class: basic +Section: programming/internals +C-Name: factor_Aurifeuille_prime +Prototype: GL +Help: _factor_Aurifeuille_prime(p,d): return an algebraic factor of Phi_d(p), p prime + +Function: _forcomposite_init +Class: gp2c_internal +Help: Initialize forcomposite_t. +Description: + (forcomposite,int):void forcomposite_init(&$1, $2, NULL) + (forcomposite,int,?int):void forcomposite_init(&$1, $2, $3) + +Function: _forcomposite_next +Class: gp2c_internal +Help: Compute the next composite. +Description: + (forcomposite):int forcomposite_next(&$1) + +Function: _formatcode +Class: gp2c_internal +Description: + (#small):void $1 + (small):small %ld + (small_int):small_int %d + (#str):void $%1 + (str):str %s + (gen):gen %Ps + +Function: _forpart_init +Class: gp2c_internal +Help: Initialize forpart_t +Description: + (forpart,small,?gen,?gen):void forpart_init(&$1, $2, $3, $4) + +Function: _forpart_next +Class: gp2c_internal +Help: Compute the next part +Description: + (forpart):vecsmall forpart_next(&$1) + +Function: _forperm_init +Class: gp2c_internal +Help: Initialize forperm_t +Description: + (forperm,gen):void forperm_init(&$1, $2) + +Function: _forperm_next +Class: gp2c_internal +Help: Compute the next permutation +Description: + (forperm):vecsmall forperm_next(&$1) + +Function: _forprime_init +Class: gp2c_internal +Help: Initialize forprime_t. +Description: + (forprime,int,?int):void forprime_init(&$1, $2, $3); + +Function: _forprime_next +Class: gp2c_internal +Help: Compute the next prime from the diffptr table. +Description: + (*small,*bptr):void NEXT_PRIME_VIADIFF($1, $2) + +Function: _forprime_next_ +Class: gp2c_internal +Help: Compute the next prime. +Description: + (forprime):int forprime_next(&$1) + +Function: _forprimestep_init +Class: gp2c_internal +Help: Initialize forprime_t. +Description: + (forprime,int,?int,int):void forprimestep_init(&$1,$2,$3,$4); + +Function: _forsubset_init +Class: gp2c_internal +Help: Initialize forsubset_t +Description: + (forsubset,small):void forallsubset_init(&$1, $2) + (forsubset,gen):void forsubset_init(&$1, $2) + +Function: _forsubset_next +Class: gp2c_internal +Help: Compute the next subset +Description: + (forsubset):vecsmall forsubset_next(&$1) + +Function: _forvec_init +Class: gp2c_internal +Help: Initializes parameters for forvec. +Description: + (forvec, gen, ?small):void forvec_init(&$1, $2, $3) + +Function: _forvec_next +Class: gp2c_internal +Help: Initializes parameters for forvec. +Description: + (forvec):vec forvec_next(&$1) + +Function: _gc_needed +Class: gp2c_internal +Description: + (pari_sp):bool gc_needed($1, 1) + +Function: _gerepileall +Class: gp2c_internal +Description: + (pari_sp,gen):void:parens $2 = gerepilecopy($1, $2) + (pari_sp,gen,...):void gerepileall($1, ${nbarg 1 sub}, ${stdref 3 code}) + +Function: _gerepileupto +Class: gp2c_internal +Description: + (pari_sp, int):int gerepileuptoint($1, $2) + (pari_sp, mp):mp gerepileuptoleaf($1, $2) + (pari_sp, vecsmall):vecsmall gerepileuptoleaf($1, $2) + (pari_sp, vec):vec gerepileupto($1, $2) + (pari_sp, gen):gen gerepileupto($1, $2) + +Function: _header_algebras +Class: header +Section: algebras +Doc: + \section{Associative and central simple algebras} + + This section collects functions related to associative algebras and central + simple algebras (CSA) over number fields. + + \subsec{Algebra definitions} %GPHELPskip + + Let $A$ be a finite-dimensional unital associative algebra over a field $K$. + The algebra $A$ is \emph{central} if its center is $K$ and it is + \emph{simple} if it has no nontrivial two-sided ideals. + + We provide functions to handle associative algebras of finite + dimension over~$\Q$ or~$\F_{p}$. We represent them by the left multiplication + table on a basis over the prime subfield; the function \kbd{algtableinit} + creates the object representing an associative algebra. We also provide + functions to handle central simple algebras over a number field $K$. We + represent them either by the left multiplication table on a basis over the + center $K$ or by a cyclic algebra (see below); the function~\kbd{alginit} + creates the object representing a central simple algebra. + + The set of elements of an algebra~$A$ that annihilate every simple left + $A$-module is a two-sided ideal, called the \emph{Jacobson radical} of~$A$. + If the Jacobson radical is trivial, the algebra is \emph{semisimple}: it is + isomorphic to a direct product of simple algebras. The + dimension of a CSA over its center $K$ is always a + square $d^{2}$ and the integer $d$ is called the \emph{degree} of the + algebra over~$K$. A CSA over a field~$K$ is always isomorphic to~$M_{k}(D)$ + for some integer~$k$ and some central division algebra~$D$ of degree~$e$: + the integer~$e$ is the \emph{index} of the algebra. + + Let $L/K$ be a cyclic extension of degree $d$, let $\sigma$ be a + generator of $\text{Gal}(L/K)$ and let $b\in K^{*}$. Then the + \emph{cyclic algebra} $(L/K,\sigma,b)$ is the algebra + $\bigoplus_{i=0}^{d-1}x^{i}L$ with $x^{d}=b$ and $\ell x=x\sigma(\ell)$ for + all~$\ell\in L$. The algebra $(L/K,\sigma,b)$ is a central simple $K$-algebra + of degree~$d$, and it is an $L$-vector space. Left multiplication is + $L$-linear and induces a $K$-algebra isomorphism + $(L/K,\sigma,b)\otimes_{K} L\to M_{d}(L)$. + + Let $K$ be a nonarchimedean local field with uniformizer $\pi$, and let + $L/K$ be the unique unramified extension of degree $d$. Then every central + simple algebra $A$ of degree $d$ over $K$ is isomorphic to + $(L/K, \Frob, \pi^{h})$ for some integer $h$. The element $h/d\in + \Q/\Z$ is called the \emph{Hasse invariant} of $A$. + + Let ${\bf H}$ be the Hamilton quaternion algebra, that is the 4-dimensional + algebra over $\R$ with basis~$1,i,j,ij$ and multiplication given + by~$i^{2}=j^{2}=-1$ and $ji=-ij$, which is also the cyclic + algebra~$(\C/\R,z\mapsto \bar{z},-1)$. + Every central simple algebra $A$ of degree $d$ over $\R$ is isomorphic + to~$M_{d}(\R)$ or $M_{d/2}({\bf H})$. We define the \emph{Hasse invariant} + of~$A$ to be~$0\in\Q/\Z$ in the first case and~$1/2\in\Q/\Z$ in the second + case. + + \subsec{Orders in algebras} %GPHELPskip + + Let~$A$ be an algebra of finite dimension over~$\Q$. An \emph{order} + in~$A$ is a finitely generated $\Z$-submodule~${\cal O}$ such + that~$\Q{\cal O} = A$, that is also a subring with unit. + By default the data computed by~\kbd{alginit} contains a~$\Z$-basis of a + maximal order~${\cal O}_{0}$. We define natural + orders in central simple algebras defined by a cyclic algebra or by a + multiplication table over the center. Let~$A = (L/K,\sigma,b) = + \bigoplus_{i=0}^{d-1}x^{i}L$ be a cyclic algebra over a number field~$K$ of + degree~$n$ with ring of integers~$\Z_{K}$. Let~$\Z_{L}$ be the ring of integers + of~$L$, and assume that~$b$ is integral. Then the submodule~${\cal O} = + \bigoplus_{i=0}^{d-1}x^{i}\Z_{L}$ is an order in~$A$, called the + \emph{natural order}. Let~$\omega_{0},\dots,\omega_{nd-1}$ be a~$\Z$-basis + of~$\Z_{L}$. The \emph{natural basis} of~${\cal O}$ + is~$b_{0},\dots,b_{nd^{2}-1}$ + where~$b_{i} = x^{i/(nd)}\omega_{(i \mod nd)}$. Now let~$A$ be a central simple + algebra of degree~$d$ over a number field~$K$ of degree~$n$ with ring of + integers~$\Z_{K}$. Let~$e_{0},\dots,e_{d^{2}-1}$ be a basis of~$A$ over~$K$ and + assume that the left multiplication table of~$A$ on~$(e_{i})$ is integral. Then + the submodule~${\cal O} = \bigoplus_{i=0}^{d^{2}-1}\Z_{K} e_{i}$ is an order + in~$A$, called the \emph{natural order}. Let~$\omega_{0},\dots,\omega_{n-1}$ be + a~$\Z$-basis of~$\Z_{K}$. The \emph{natural basis} of~${\cal O}$ + is~$b_{0},\dots,b_{nd^{2}-1}$ where~$b_{i} = \omega_{(i \mod n)}e_{i/n}$. + + \subsec{Lattices in algebras} %GPHELPskip + + We also provide functions to handle full lattices in algebras over~$\Q$. A + full lattice~$J\subset A$ is represented by a $2$-component \typ{VEC}~$[I,t]$ + representing~$J = tI$, where + + \item $I$ is an integral nonsingular upper-triangular matrix representing a + sublattice of~${\cal O}_{0}$ expressed on the integral basis, and + + \item $t\in\Q_{>0}$ is a \typ{INT} or \typ{FRAC}. + + For the sake of efficiency you should use matrices~$I$ that are primitive and + in Hermite Normal Form; this makes the representation unique. No GP function + uses this property, but all GP functions return lattices in this form. The + prefix for lattice functions is \kbd{alglat}. + + \subsec{GP conventions for algebras} %GPHELPskip + + As with number fields, we represent elements of central simple algebras + in two ways, called the \emph{algebraic representation} and the \emph{basis + representation}, and you can convert betweeen the two with the functions + \kbd{algalgtobasis} and \kbd{algbasistoalg}. In every central simple algebra + object, we store a~$\Z$-basis of an order~${\cal O}_{0}$, and the basis + representation is simply a \typ{COL} with coefficients in~$\Q$ expressing the + element in that basis. If no maximal order was computed by~\kbd{alginit}, + then~${\cal O}_{0}$ is the natural order. If a maximal order was computed, + then~${\cal O}_{0}$ is a maximal order containing the natural order. For a cyclic + algebra~$A = (L/K,\sigma,b)$, the algebraic representation is a \typ{COL} with + coefficients in~$L$ representing the element in the decomposition~$A = + \bigoplus_{i=0}^{d-1}x^{i}L$. For a central simple algebra defined by a + multiplication table over its center~$K$ on a basis~$(e_{i})$, the algebraic + representation is a \typ{COL} with coefficients in~$K$ representing the element + on the basis~$(e_{i})$. + + \misctitle{Warning} The coefficients in the decomposition~$A = + \bigoplus_{i=0}^{d-1}x^{i}L$ are not the same as those in the decomposition~$A + = \bigoplus_{i=0}^{d-1}Lx^{i}$! The $i$-th coefficients are related by + conjugating by~$x^{i}$, which on~$L$ amounts to acting by~$\sigma^{i}$. + + \misctitle{Warning} For a central simple algebra over $\Q$ defined by a + multiplication table, we cannot distinguish between the basis and the algebraic + representations from the size of the vectors. The behavior is then to always + interpret the column vector as a basis representation if the coefficients are + \typ{INT} or \typ{FRAC}, and as an algebraic representation if the coefficients + are \typ{POL} or \typ{POLMOD}. + + An element of the Hamilton quaternion algebra ${\bf H}$ can be represented as a + \typ{REAL}, a \typ{COMPLEX} representing an element of~$\C = \R+\R i\subset + {\bf H}$, or a $4$ components \typ{COL} of \typ{REAL} encoding the coordinates + on the basis~$1,i,j,ij$. + +Function: _header_combinatorics +Class: header +Section: combinatorics +Doc: + \section{Combinatorics}\label{se:combinat} + + Permutations are represented in gp as \typ{VECSMALL}s and can be input + directly as \kbd{Vecsmall([1,3,2,4])} or obtained from the iterator + \kbd{forperm}: + \bprog + ? forperm(3, p, print(p)) \\ iterate through S_3 + Vecsmall([1, 2, 3]) + Vecsmall([1, 3, 2]) + Vecsmall([2, 1, 3]) + Vecsmall([2, 3, 1]) + Vecsmall([3, 1, 2]) + Vecsmall([3, 2, 1]) + @eprog + + Permutations can be multiplied via \kbd{*}, raised to some power using + \kbd{\pow}, inverted using \kbd{\pow(-1)}, conjugated as + \kbd{p * q * p\pow(-1)}. Their order and signature are available via + \kbd{permorder} and \kbd{permsign}. + +Function: _header_conversions +Class: header +Section: conversions +Doc: + \section{Conversions and similar elementary functions or commands} + \label{se:conversion} + + \noindent + Many of the conversion functions are rounding or truncating operations. In + this case, if the argument is a rational function, the result is the + Euclidean quotient of the numerator by the denominator, and if the argument + is a vector or a matrix, the operation is done componentwise. This will not + be restated for every function. + +Function: _header_default +Class: header +Section: default +Doc: + \section{GP defaults} + \label{se:gp_defaults} This section documents the GP defaults, + that can be set either by the GP function \tet{default} or in your GPRC. + Be sure to check out \tet{parisize} and \tet{parisizemax} ! + +Function: _header_elliptic_curves +Class: header +Section: elliptic_curves +Doc: + \section{Elliptic curves} + + \subsec{Elliptic curve structures} %GPHELPskip + An elliptic curve is given by a Weierstrass model\sidx{Weierstrass equation} + $$ + y^{2} + a_{1} xy + a_{3} y = x^{3} + a_{2} x^{2} + a_{4} x + a_{6}, + $$ + whose discriminant is nonzero. One can also define an elliptic curve with + a\sidx{short Weierstrass equation} + $$ + y^{2} = x^{3} + a_{4} x + a_{6}. + $$ + Affine points on \kbd{E} are represented as + two-component vectors \kbd{[x,y]}; the point at infinity, i.e.~the identity + element of the group law, is represented by the one-component vector + \kbd{[0]}. + + Given a vector of coefficients $[a_{1},a_{2},a_{3},a_{4},a_{6}]$ or $[a_{4},a_{6}]$, the function + \tet{ellinit} initializes and returns an \tev{ell} structure. An additional + optional argument allows to specify the base field in case it cannot be + inferred from the curve coefficients. This structure contains data needed by + elliptic curve related functions, and is generally passed as a first argument. + Expensive data are skipped on initialization: they will be dynamically + computed when (and if) needed, and then inserted in the structure. The + precise layout of the \tev{ell} structure is left undefined and should never + be used directly. The following \idx{member functions} are available, + depending on the underlying domain. + + \misctitle{All domains} %GPHELPskip + + \item \tet{a1}, \tet{a2}, \tet{a3}, \tet{a4}, \tet{a6}: coefficients of the + elliptic curve. + + \item \tet{b2}, \tet{b4}, \tet{b6}, \tet{b8}: $b$-invariants of the curve; in + characteristic $\neq 2$, for $Y = 2y + a_{1}x + a_{3}$, the curve equation + becomes + $$ Y^{2} = 4 x^{3} + b_{2} x^{2} + 2b_{4} x + b_{6} =: g(x). $$ + + \item \tet{c4}, \tet{c6}: $c$-invariants of the curve; in characteristic $\neq + 2,3$, for $X = x + b_{2}/12$ and $Y = 2y + a_{1}x + a_{3}$, the curve equation + becomes + $$ Y^{2} = 4 X^{3} - (c_{4}/12) X - (c_{6}/216). $$ + + \item \tet{disc}: discriminant of the curve. This is only required to be + nonzero, not necessarily a unit. + + \item \tet{j}: $j$-invariant of the curve. + + \noindent These are used as follows: + \bprog + ? E = ellinit([0,0,0, a4,a6]); + ? E.b4 + %2 = 2*a4 + ? E.disc + %3 = -64*a4^3 - 432*a6^2 + @eprog + + \misctitle{Curves over $\C$} %GPHELPskip + + This in particular includes curves defined over $\Q$. All member functions in + this section return data, as it is currently stored in the structure, if + present; and otherwise compute it to the default accuracy, that was fixed + \emph{at the time of ellinit} (via a \typ{REAL} $D$ domain argument, or + \kbd{realprecision} by default). The function \tet{ellperiods} allows to + recompute (and cache) the following data to \emph{current} + \kbd{realprecision}. + + \item \tet{area}: volume of the complex lattice defining $E$. + + \item \tet{roots} is a vector whose three components contain the complex + roots of the right hand side $g(x)$ of the attached $b$-model $Y^{2} = g(x)$. + If the roots are all real, they are ordered by decreasing value. If only one + is real, it is the first component. + + \item \tet{omega}: $[\omega_{1},\omega_{2}]$, periods forming a basis of the + complex lattice defining $E$. The first component $\omega_{1}$ is the + (positive) real period, in other words the integral of the N\'eron + differential $dx/(2y+a_{1}x+a_{3})$ + over the connected component of the identity component of $E(\R)$. + The second component $\omega_{2}$ is a complex period, such that + $\tau=\dfrac{\omega_{1}}{\omega_{2}}$ belongs to Poincar\'e's + half-plane (positive imaginary part); not necessarily to the standard + fundamental domain. It is normalized so that $\Im(\omega_{2}) < 0$ + and either $\Re(\omega_{2}) = 0$, when \kbd{E.disc > 0} + ($E(\R)$ has two connected components), or $\Re(\omega_{2}) = \omega_{1}/2$ + + \item \tet{eta} is a row vector containing the quasi-periods $\eta_{1}$ and + $\eta_{2}$ such that $\eta_{i} = 2\zeta(\omega_{i}/2)$, where $\zeta$ is the + Weierstrass zeta function attached to the period lattice; see + \tet{ellzeta}. In particular, the Legendre relation holds: + $\eta_{2}\omega_{1} - \eta_{1}\omega_{2} = 2\pi i$. + + \misctitle{Warning} As for the orientation of the basis of the period lattice, + beware that many sources use the inverse convention where + $\omega_{2}/\omega_{1}$ has positive imaginary part and our $\omega_{2}$ is + the negative of theirs. Our convention $\tau = \omega_{1}/\omega_{2}$ ensures + that the action of $\text{PSL}_{2}$ is the natural one: + $$[a,b;c,d]\cdot\tau = (a\tau+b)/(c\tau+d) + = (a \omega_{1} + b\omega_{2})/(c\omega_{1} + d\omega_{2}),$$ + instead of a twisted one. (Our $\tau$ is $-1/\tau$ in the above inverse + convention.) + + \misctitle{Curves over $\Q_{p}$} %GPHELPskip + + We advise to input a model defined over $\Q$ for such curves. In any case, + if you input an approximate model with \typ{PADIC} coefficients, it will be + replaced by a lift to $\Q$ (an exact model ``close'' to the one that was + input) and all quantities will then be computed in terms of this lifted + model. + + For the time being only curves with multiplicative reduction (split or + nonsplit), i.e. $v_{p}(j) < 0$, are supported by nontrivial functions. In + this case the curve is analytically isomorphic to $\bar{\Q}_{p}^{*}/q^{\Z} := + E_{q}(\bar{\Q}_{p})$, for some $p$-adic integer $q$ (the Tate period). In + particular, we have $j(q) = j(E)$. + + \item \tet{p} is the residual characteristic + + \item \tet{roots} is a vector with a single component, equal to the $p$-adic + root $e_{1}$ of the right hand side $g(x)$ of the attached $b$-model $Y^{2} + = g(x)$. The point $(e_{1},0)$ corresponds to $-1 \in \bar{\Q}_{p}^{*}/q^{\Z}$ + under the Tate parametrization. + + \item \tet{tate} returns $[u^{2},u,q,[a,b],Ei,L]$ in the notation of + Henniart-Mestre (CRAS t. 308, p.~391--395, 1989): $q$ is as above, + $u\in \Q_{p}(\sqrt{-c_{6}})$ is such that $\phi^{*} dx/(2y + a_{1}x + a_{3}) + = u dt/t$, where $\phi: E_{q}\to E$ is an isomorphism + (well defined up to sign) and $dt/t$ is the canonical invariant differential + on the Tate curve; $u^{2}\in\Q_{p}$ does not depend on $\phi$. + (Technicality: if $u\not\in\Q_{p}$, it is stored as a quadratic \typ{POLMOD}.) + The parameters $[a,b]$ satisfy $4u^{2} b \cdot \text{agm}(\sqrt{a/b},1)^{2} + = 1$ as in Theorem~2 (\emph{loc.~cit.}). + \kbd{Ei} describes the sequence of 2-isogenous curves (with kernel generated + by $[0,0]$) $E_{i}: y^{2}=x(x+A_{i})(x+A_{i}-B_{i})$ converging quadratically + towards the singular curve $E_{\infty}$. Finally, $L$ is + Mazur-Tate-Teitelbaum's ${\cal L}$-invariant, equal to $\log_{p} q / v_{p}(q)$. + + \misctitle{Curves over $\F_{q}$} %GPHELPskip + + \item \tet{p} is the characteristic of $\F_{q}$. + + \item \tet{no} is $\#E(\F_{q})$. + + \item \tet{cyc} gives the cycle structure of $E(\F_{q})$. + + \item \tet{gen} returns the generators of $E(\F_{q})$. + + \item \tet{group} returns $[\kbd{no},\kbd{cyc},\kbd{gen}]$, i.e. $E(\F_{q})$ + as an abelian group structure. + + \misctitle{Curves over $\Q$} %GPHELPskip + + All functions should return a correct result, whether the model is minimal or + not, but it is a good idea to stick to minimal models whenever + $\gcd(c_{4},c_{6})$ is easy to factor (minor speed-up). The construction + \bprog + E = ellminimalmodel(E0, &v) + @eprog\noindent replaces the original model $E_{0}$ by a minimal model $E$, + and the variable change $v$ allows to go between the two models: + \bprog + ellchangepoint(P0, v) + ellchangepointinv(P, v) + @eprog\noindent respectively map the point $P_{0}$ on $E_{0}$ to its image on + $E$, and the point $P$ on $E$ to its pre-image on $E_{0}$. + + A few routines --- namely \tet{ellgenerators}, \tet{ellidentify}, + \tet{ellsearch}, \tet{forell} --- require the optional package \tet{elldata} + (John Cremona's database) to be installed. In that case, the function + \tet{ellinit} will allow alternative inputs, e.g.~\kbd{ellinit("11a1")}. + Functions using this package need to load chunks of a large database in + memory and require at least 2MB stack to avoid stack overflows. + + \item \tet{gen} returns the generators of $E(\Q)$, if known (from John + Cremona's database) + + \misctitle{Curves over number fields} %GPHELPskip + + \item \tet{nf} return the \var{nf} structure attached to the number field + over which $E$ is defined. + + \item \tet{bnf} return the \var{bnf} structure attached to the number field + over which $E$ is defined or raise an error (if only an \var{nf} is available). + + \item \tet{omega}, \tet{eta}, \tet{area}: vectors of complex periods, + quasi-periods and lattice areas attached to the complex embeddings of $E$, + in the same order as \kbd{E.nf.roots}. + + \subsec{Reduction} %GPHELPskip + Let $E$ be a curve defined over $\Q_{p}$ given by a $p$-integral model; + if the curve has good reduction at $p$, we may define its reduction + $\tilde{E}$ over the finite field $\F_{p}$: + \bprog + ? E = ellinit([-3,1], O(5^10)); \\ @com $E/\Q_{5}$ + ? Et = ellinit(E, 5) + ? ellcard(Et) \\ @com $\tilde{E}/\F_{5}$ has 7 points + %3 = 7 + ? ellinit(E, 7) + *** at top-level: ellinit(E,7) + *** ^------------ + *** ellinit: inconsistent moduli in ellinit: 5 != 7 + @eprog\noindent + Likewise, if a curve is defined over a number field $K$ and $\goth{p}$ is a + maximal ideal with finite residue field $\F_{q}$, we define the reduction + $\tilde{E}/\F_{q}$ provided $E$ has good reduction at $\goth{p}$. + $E/\Q$ is an important special case: + \bprog + ? E = ellinit([-3,1]); + ? factor(E.disc) + %2 = + [2 4] + + [3 4] + ? Et = ellinit(E, 5); + ? ellcard(Et) \\ @com $\tilde{E} / \F_{5}$ has 7 points + %4 = 7 + ? ellinit(E, 3) \\ bad reduction at 3 + %5 = [] + @eprog\noindent General number fields are similar: + \bprog + ? K = nfinit(x^2+1); E = ellinit([x,x+1], K); + ? idealfactor(K, E.disc) \\ three primes of bad reduction + %2 = + [ [2, [1, 1]~, 2, 1, [1, -1; 1, 1]] 10] + + [ [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] 2] + + [[5, [2, 1]~, 1, 1, [-2, -1; 1, -2]] 2] + ? P = idealprimedec(K, 3); \\ a prime of good reduction + ? idealnorm(K, P) + %4 = 9 + ? Et = ellinit(E, P); + ? ellcard(Et) \\ @com $\tilde{E} / \F_{9}$ has 4 points + %6 = 4 + @eprog\noindent + If the model is not locally minimal at $\goth{p}$, the above will fail: + \kbd{elllocalred} and \kbd{ellchangecurve} allow to reduce to that case. + + Some functions such as \kbd{ellap}, \kbd{ellcard}, \kbd{ellgroup} and + \kbd{ellissupersingular} even implicitly replace the given equation by + a local minimal model and consider the group of nonsingular points + $\tilde{E}^{ns}$ so they make sense even when the curve has bad reduction. + +Function: _header_graphic +Class: header +Section: graphic +Doc: + \section{Plotting functions} + + Although plotting is not even a side purpose of PARI, a number of plotting + functions are provided. There are three types of graphic functions. + + \subsec{High-level plotting functions} (all the functions starting with + \kbd{ploth}) in which the user has little to do but explain what type of plot + he wants, and whose syntax is similar to the one used in the preceding + section. + + \subsec{Low-level plotting functions} (called \var{rectplot} functions, + sharing the prefix \kbd{plot}), where every drawing primitive (point, line, + box, etc.) is specified by the user. These low-level functions work as + follows. You have at your disposal 16 virtual windows which are filled + independently, and can then be physically ORed on a single window at + user-defined positions. These windows are numbered from 0 to 15, and must be + initialized before being used by the function \kbd{plotinit}, which specifies + the height and width of the virtual window (called a \var{rectwindow} in the + sequel). At all times, a virtual cursor (initialized at $[0,0]$) is attached + to the window, and its current value can be obtained using the function + \kbd{plotcursor}. + + A number of primitive graphic objects (called \var{rect} objects) can then + be drawn in these windows, using a default color attached to that window + (which can be changed using the \kbd{plotcolor} function) and only the part + of the object which is inside the window will be drawn, with the exception of + polygons and strings which are drawn entirely. The ones sharing the prefix + \kbd{plotr} draw relatively to the current position of the virtual cursor, + the others use absolute coordinates. Those having the prefix \kbd{plotrecth} + put in the rectwindow a large batch of rect objects corresponding to the + output of the related \kbd{ploth} function. + + Finally, the actual physical drawing is done using \kbd{plotdraw}. The + rectwindows are preserved so that further drawings using the same windows at + different positions or different windows can be done without extra work. To + erase a window, use \kbd{plotkill}. It is not possible to partially erase a + window: erase it completely, initialize it again, then fill it with the + graphic objects that you want to keep. + + In addition to initializing the window, you may use a scaled window to + avoid unnecessary conversions. For this, use \kbd{plotscale}. As long as this + function is not called, the scaling is simply the number of pixels, the + origin being at the upper left and the $y$-coordinates going downwards. + + Plotting functions are platform independent, but a number of graphical + drivers are available for screen output: X11-windows (including + Openwindows and Motif), Windows's Graphical Device Interface, and the + FLTK graphical libraries and one may even write the graphical objects to a + PostScript or SVG file and use an external viewer to open it. The physical + window opened by \kbd{plotdraw} or any of the \kbd{ploth*} functions is + completely separated from \kbd{gp} (technically, a \kbd{fork} is done, and + all memory unrelated to the graphics engine is immediately freed in the child + process), which means you can go on working in the current \kbd{gp} session, + without having to kill the window first. This window can be closed, enlarged + or reduced using the standard window manager functions. No zooming procedure is + implemented though. + + \subsec{Functions for PostScript or SVG output} in the same way that + \kbd{printtex} allows you to have a \TeX\ output + corresponding to printed results, the functions \kbd{plotexport}, + \kbd{plothexport} and \kbd{plothrawexport} convert a plot to a character + string in either \tet{PostScript} or \tet{Scalable Vector Graphics} format. + This string can then be written to a file in the customary way, using + \kbd{write}. These export routines are available even if no Graphic Library is. + \smallskip + +Function: _header_hypergeometric_motives +Class: header +Section: hypergeometric_motives +Doc: + \section{Hypergeometric Motives} + + \subsec{Templates} %GPHELPskip + + A \emph{hypergeometric template} is a pair of multisets (i.e., sets with + possibly repeated elements) of rational numbers + $(\alpha_{1},\dots,\alpha_{d})$ and $(\beta_{1},\dots,\beta_{d})$ + having the same number of elements, and we set + $$A(x)=\prod_{1\le j\le d}(x-e^{2\pi i\alpha_{j}}),\quad + B(x)=\prod_{1\le k\le d}(x-e^{2\pi i\beta_{k}})\;.$$ + We make the following assumptions: + + \item $\alpha_{j}-\beta_{k}\notin\Z$ for all $j$ and $k$, or + equivalently $\gcd(A,B)=1$. + + \item $\alpha_{j}\notin\Z$ for all $j$, or equivalently $A(1)\ne0$. + + \item our template is \emph{defined over $\Q$}, in other words + $A,B\in\Z[x]$, or equivalently if some $a/D$ with $\gcd(a,D)=1$ occurs + in the $\alpha_{j}$ or $\beta_{k}$, then all the $b/D$ modulo $1$ with + $\gcd(b,D)=1$ also occur. + + The last assumption allows to abbreviate $[a_{1}/D,\dots,a_{\phi(D)}/D]$ + (where the $a_{i}$ range in $(\Z/D\Z)^{*}$) to $[D]$. We thus have two possible + ways of giving a hypergeometric template: either by the two vectors + $[\alpha_{1},\dots,\alpha_{d}]$ and $[\beta_{1},\dots,\beta_{d}]$, or by their + denominators $[D_{1},\dots,D_{m}]$ and $[E_{1},\dots,E_{n}]$ , which are + called the + \emph{cyclotomic parameters}; note that $\sum_{j}\phi(D_{j}) + = \sum_{k}\phi(E_{k}) = d$. + A third way is to give the \emph{gamma vector} $(\gamma_{n})$ + defined by $A(X)/B(X)=\prod_{n}(X^{n}-1)^{\gamma_{n}}$, which satisfies + $\sum_{n} n\gamma_{n}=0$. To any such data we associate a hypergeometric template + using the function \kbd{hgminit}; then the $\alpha_{j}$ and $\beta_{k}$ + are obtained using \kbd{hgmalpha}, cyclotomic parameters + using \kbd{hgmcyclo} and the gamma vectors using \kbd{hgmgamma}. + + To such a hypergeometric template is associated a number of additional + parameters, for which we do not give the definition but refer to the survey + \emph{Hypergeometric Motives} by Roberts and Villegas, + \kbd{https://arxiv.org/abs/2109.00027}: + the degree $d$, the \emph{weight} $w$, a \emph{Hodge polynomial}~$P$, + a \emph{Tate twist} $T$, and a normalizing M-factor + $M = \prod_{n} n^{n\gamma_{n}}$. The \kbd{hgmparams} function returns + $$[d,w,[P,T],M]\;.$$ + Example with cyclotomic parameters $[5],[1,1,1,1]$: + \bprog + ? H = hgminit([5]); \\ [1,1,1,1] can be omitted + ? hgmparams(H) + %2 = [4, 3, [x^3+x^2+x+1,0], 3125] + ? hgmalpha(H) + %3 = [[1/5, 2/5, 3/5, 4/5], [0, 0, 0, 0]] + ? hgmcyclo(H) + %4 = [Vecsmall([5]), Vecsmall([1, 1, 1, 1])] + ? hgmgamma(H) + %5 = Vecsmall([-5,0,0,0,1]) \\ A/B = (x^5-1) / (x-1)^5 + @eprog + + \subsec{Motives} %GPHELPskip + + A \emph{hypergeometric motive} (HGM for short) is a pair $(H,t)$, where + $H$ is a hypergeometric template and $t\in\Q^{*}$. To such a motive and a + finite field $\F_{q}$ one can associate via an explicit but + complicated formula an \emph{integer} $N(H,t; q)$, see Beukers, Cohen and + Mellit, \emph{Finite hypergeometric functions} Pure and Applied Math + Quarterly 11 (2015), pp 559 - 589, \kbd{https://arxiv.org/abs/1505.02900}. + + \misctitle{Warning} Depending on the authors, $t$ may have to be replaced + with $1/t$. The \kbd{Pari/GP} convention is the same as the one in + \kbd{Magma}, but is the inverse of the one in the last reference. + + This formula does not make sense and is not valid for \emph{bad + primes}~$p$: a \emph{wild prime} is a prime which divides a denominator of + the $\alpha_{j}$ or $\beta_{i}$. If a prime $p$ is not wild, it can be + \emph{good} if $v_{p}(t)=v_{p}(t-1)=0$, or \emph{tame} otherwise. + The \emph{local Euler factor} $P_{p}$ at a good prime $p$ is then given by + the usual formula + $$-\log P_{p}(T) = \sum_{f\ge1} \dfrac{N(H,t; p^{f}) T^{f}}{f} \;,$$ + and in the case of HGM's $P_{p}$ is always a polynomial (note that the Euler + factor used in the global $L$-function is $1/P_{p}(p^{-s})$). At a tame prime + $p$ it + is necessary to modify the above formula, and usually (but not always) the + degree of the local Euler factor decreases. Wild primes are currently not + implemented by a formula but can be guessed via the global functional + equation (see the next section). Continuing the previous example, we find + \bprog + ? hgmeulerfactor(H, -1, 3) \\ good prime + %4 = 729*x^4 + 135*x^3 + 45*x^2 + 5*x + 1 + ? hgmeulerfactor(H, -1, 2) \\ tame prime + %5 = 16*x^3 + 6*x^2 + x + 1 + ? hgmeulerfactor(H, -1, 5) \\ wild primes not implemented + %6 = 0 + @eprog\noindent + To obtain the Euler factor at wild primes, use \kbd{lfuneuler} once + the global $L$-function is computed. + + \subsec{The Global $L$-function} %GPHELPskip + + A theorem of Katz tells us that if one suitably defines $P_{p}(T)$ for + all primes $p$ including the wild ones, then the $L$-function defined + by $L(H,s)=\prod_{p} P_{p}(p^{-s})^{-1}$ is motivic, + with analytic continuation and functional equation, + as used in the $L$-function package of \kbd{Pari/GP}. The command + \kbd{L = lfunhgm(H,t)} creates such an $L$-function. In particular it must + guess the local Euler factors at wild primes, which can be very expensive + when the conductor \kbd{lfunparams}$(L)[1]$ is large. + + In our example, \kbd{L = lfunhgm(H,1/64)} finishes in about 20 seconds + (the conductor is only 525000); + this $L$-function can then be used with all the functions of the + \kbd{lfun} package. For instance we can now obtain the global conductor and + check the Euler factors at all bad primes: + \bprog + ? [N] = lfunparams(L); N \\ the conductor + %7 = 525000 + ? factor(N) + %8 = + [2 3] + + [3 1] + + [5 5] + + [7 1] + + ? lfuneuler(L,2) + %9 = 1/(-x + 1) + ? lfuneuler(L,3) + %10 = 1/(81*x^3 + 6*x^2 - 4*x + 1) + ? lfuneuler(L,5) + %11 = 1 + ? lfuneuler(L,7) + %12 = 1/(2401*x^3 + 301*x^2 + x + 1) + @eprog + + Two additional functions related to the global $L$-function are available + which do \emph{not} require its full initialization: + \kbd{hgmcoefs(H,t,n)} computes + the first $n$ coefficients of the $L$-function by setting all wild Euler + factors to $1$; this will be identical to \kbd{lfunan(L,n)} when this is + indeed the case (as in the above example: only $5$ is wild), otherwise all + coefficients divisible by a wild prime will be wrong. + + The second is the function \kbd{hgmcoef(H,t,n)} which only computes the + $n$th coefficient of the global $L$-function. It gives an error if $n$ + is divisible by a wild prime. Compare \kbd{hgmcoefs(H,1/64,7\^{}6)[7\^{}6]} + which requires more than 1 minute (it computes more than 100000 coefficients), + with \kbd{hgmcoef(H,1/64,7\^{}6)} which outputs $-25290600$ instantaneously. + +Function: _header_l_functions +Class: header +Section: l_functions +Doc: + \section{$L$-functions} + + This section describes routines related to $L$-functions. We first introduce + the basic concept and notations, then explain how to represent them in GP. + Let $\Gamma_{\R}(s) = \pi^{-s/2}\Gamma(s/2)$, where $\Gamma$ is Euler's gamma + function. Given $d \geq 1$ and a $d$-tuple $A=[\alpha_{1},\dots,\alpha_{d}]$ + of complex numbers, we let $\gamma_{A}(s) = \prod_{\alpha \in A} + \Gamma_{\R}(s + \alpha)$. + + Given a sequence $a = (a_{n})_{n\geq 1}$ of complex numbers + (such that $a_{1} = 1$), + a positive \emph{conductor} $N \in \Z$, and a \emph{gamma factor} + $\gamma_{A}$ as above, we consider the Dirichlet series + $$ L(a,s) = \sum_{n\geq 1} a_{n} n^{-s} $$ + and the attached completed function + $$ \Lambda(a,s) = N^{s/2}\gamma_{A}(s) \cdot L(a,s). $$ + + Such a datum defines an \emph{$L$-function} if it satisfies the three + following assumptions: + + \item [Convergence] The $a_{n} = O_{\epsilon}(n^{k_{1}+\epsilon})$ + have polynomial growth, equivalently $L(s)$ converges absolutely in some + right half-plane $\Re(s) > k_{1} + 1$. + + \item [Analytic continuation] $L(s)$ has a meromorphic continuation to the + whole complex plane with finitely many poles. + + \item [Functional equation] There exist an integer $k$, a complex number + $\epsilon$ (usually of modulus~$1$), and an attached sequence $a^{*}$ + defining both an $L$-function $L(a^{*},s)$ satisfying the above two assumptions + and a completed function $\Lambda(a^{*},s) = N^{s/2}\gamma_{A}(s) \cdot + L(a^{*},s)$, such that + $$\Lambda(a,k-s) = \epsilon \Lambda(a^{*},s)$$ + for all regular points. + + More often than not in number theory we have $a^{*} = \overline{a}$ (which + forces $|\epsilon| = 1$), but this needs not be the case. If $a$ is a real + sequence and $a = a^{*}$, we say that $L$ is \emph{self-dual}. We do not assume + that the $a_{n}$ are multiplicative, nor equivalently that $L(s)$ has an Euler + product. + + \misctitle{Remark} + Of course, $a$ determines the $L$-function, but the (redundant) datum $a,a^{*}, + A, N, k, \epsilon$ describes the situation in a form more suitable for fast + computations; knowing the polar part $r$ of $\Lambda(s)$ (a rational function + such that $\Lambda-r$ is holomorphic) is also useful. A subset of these, + including only finitely many $a_{n}$-values will still completely determine $L$ + (in suitable families), and we provide routines to try and compute missing + invariants from whatever information is available. + + \misctitle{Important Caveat} + The implementation assumes that the implied constants in the $O_{\epsilon}$ are + small. In our generic framework, it is impossible to return proven results + without more detailed information about the $L$ function. The intended use of + the $L$-function package is not to prove theorems, but to experiment and + formulate conjectures, so all numerical results should be taken with a grain + of salt. One can always increase \kbd{realbitprecision} and recompute: the + difference estimates the actual absolute error in the original output. + + \misctitle{Note} The requested precision has a major impact on runtimes. + Because of this, most $L$-function routines, in particular \kbd{lfun} itself, + specify the requested precision in \emph{bits}, not in decimal digits. + This is transparent for the user once \tet{realprecision} or + \tet{realbitprecision} are set. We advise to manipulate precision via + \tet{realbitprecision} as it allows finer granularity: \kbd{realprecision} + increases by increments of 64 bits, i.e. 19 decimal digits at a time. + + \subsec{Theta functions} %GPHELPskip + + Given an $L$-function as above, we define an attached theta function + via Mellin inversion: for any positive real $t > 0$, we let + $$ \theta(a,t) := \dfrac{1}{2\pi i}\int_{\Re(s) = c} t^{-s} \Lambda(s)\, ds $$ + where $c$ is any positive real number $c > k_{1}+1$ such that $c + \Re(a) > 0$ + for all $a\in A$. In fact, we have + $$\theta(a,t) = \sum_{n\geq 1} a_{n} K(nt/N^{1/2}) + \quad\text{where}\quad + K(t) := \dfrac{1}{2\pi i}\int_{\Re(s) = c} t^{-s} \gamma_{A}(s)\, ds.$$ + Note that this function is analytic and actually makes sense for complex $t$, + such that $\Re(t^{2/d}) > 0$, i.e. in a cone containing the positive real + half-line. The functional equation for $\Lambda$ translates into + $$ \theta(a,1/t) - \epsilon t^{k}\theta(a^{*},t) = P_{\Lambda}(t), $$ + where $P_{\Lambda}$ is an explicit polynomial in $t$ and $\log t$ given by the + Taylor expansion of the polar part of $\Lambda$: there are no $\log$'s if + all poles are simple, and $P = 0$ if $\Lambda$ is entire. The values + $\theta(t)$ are generally easier to compute than the $L(s)$, and this + functional equation provides a fast way to guess possible values for + missing invariants in the $L$-function definition. + + \subsec{Data structures describing $L$ and theta functions} %GPHELPskip + + We have 3 levels of description: + + \item an \tet{Lmath} is an arbitrary description of the underlying + mathematical situation (to which e.g., we associate the $a_{p}$ as traces of + Frobenius elements); this is done via constructors to be described in the + subsections below. + + \item an \tet{Ldata} is a computational description of situation, containing + the complete datum ($a,a^{*},A,k,N,\epsilon,r$). Where $a$ and $a^{*}$ describe + the coefficients (given $n,b$ we must be able to compute $[a_{1},\dots,a_{n}]$ + with bit accuracy $b$), $A$ describes the Euler factor, the (classical) weight + is $k$, $N$ is the conductor, and $r$ describes the polar part of $L(s)$. + This is obtained via the function \tet{lfuncreate}. N.B. For motivic + $L$-functions, the motivic weight $w$ is $w = k-1$; but we also support + nonmotivic $L$-functions. + + \misctitle{Technical note} When some components of an \kbd{Ldata} cannot be + given exactly, usually $r$ or $\epsilon$, the \kbd{Ldata} may be given as a + \emph{closure}. When evaluated at a given precision, the closure must return + all components as exact data or floating point numbers at the requested + precision, see \kbd{??lfuncreate}. The reason for this technicality is that + the accuracy to which we must compute is not bounded a priori and unknown + at this stage: it depends on the domain where we evaluate the $L$-function. + + \item an \tet{Linit} contains an \kbd{Ldata} and everything needed for fast + \emph{numerical} computations. It specifies the functions to be considered + (either $L^{(j)}(s)$ or $\theta^{(j)}(t)$ for derivatives of order $j \leq + m$, where $m$ is now fixed) and specifies a \emph{domain} which limits + the range of arguments ($t$ or $s$, respectively to certain cones and + rectangular regions) and the output accuracy. This is obtained via the + functions \tet{lfuninit} or \tet{lfunthetainit}. + + All the functions which are specific to $L$ or theta functions share the + prefix \kbd{lfun}. They take as first argument either an \kbd{Lmath}, an + \kbd{Ldata}, or an \kbd{Linit}. If a single value is to be computed, + this makes no difference, but when many values are needed (e.g. for plots or + when searching for zeros), one should first construct an \kbd{Linit} + attached to the search range and use it in all subsequent calls. + If you attempt to use an \kbd{Linit} outside the range for which it was + initialized, a warning is issued, because the initialization is + performed again, a major inefficiency: + \bprog + ? Z = lfuncreate(1); \\ Riemann zeta + ? L = lfuninit(Z, [1/2, 0, 100]); \\ zeta(1/2+it), |t| < 100 + ? lfun(L, 1/2) \\ OK, within domain + %3 = -1.4603545088095868128894991525152980125 + ? lfun(L, 0) \\ not on critical line ! + *** lfun: Warning: lfuninit: insufficient initialization. + %4 = -0.50000000000000000000000000000000000000 + ? lfun(L, 1/2, 1) \\ attempt first derivative ! + *** lfun: Warning: lfuninit: insufficient initialization. + %5 = -3.9226461392091517274715314467145995137 + @eprog + + For many $L$-functions, passing from \kbd{Lmath} to an \kbd{Ldata} is + inexpensive: in that case one may use \kbd{lfuninit} directly from the + \kbd{Lmath} even when evaluations in different domains are needed. The + above example could equally have skipped the \kbd{lfuncreate}: + \bprog + ? L = lfuninit(1, [1/2, 0, 100]); \\ zeta(1/2+it), |t| < 100 + @eprog\noindent In fact, when computing a single value, you can even skip + \kbd{lfuninit}: + \bprog + ? L = lfun(1, 1/2, 1); \\ zeta'(1/2) + ? L = lfun(1, 1+x+O(x^5)); \\ first 5 terms of Taylor expansion at 1 + @eprog\noindent Both give the desired results with no warning. + + \misctitle{Complexity} + The implementation requires $O(N(|t|+1))^{1/2}$ coefficients $a_{n}$ + to evaluate $L$ of conductor $N$ at $s = \sigma + i t$. + + We now describe the available high-level constructors, for built-in $L$ + functions. + + \subsec{Dirichlet $L$-functions} %GPHELPskip + + Given a Dirichlet character $\chi:(\Z/N\Z)^{*}\to \C$, we let + $$L(\chi, s) = \sum_{n\geq 1} \chi(n) n^{-s}.$$ + Only primitive characters are supported. Given a nonzero + integer $D$, the \typ{INT} $D$ encodes the function $L((D_{0}/.), s)$, for the + quadratic Kronecker symbol attached to the fundamental discriminant + $D_{0} = \kbd{coredisc}(D)$. This includes Riemann $\zeta$ function via the + special case $D = 1$. + + More general characters can be represented in a variety of ways: + + \item via Conrey notation (see \tet{znconreychar}): $\chi_{N}(m,\cdot)$ + is given as the \typ{INTMOD} \kbd{Mod(m,N)}. + + \item via a \var{znstar} structure describing the abelian group + $(\Z/N\Z)^{*}$, where the character is given in terms of the \var{znstar} + generators: + \bprog + ? G = znstar(100, 1); \\ (Z/100Z)^* + ? G.cyc \\ ~ Z/20 . g1 + Z/2 . g2 for some generators g1 and g2 + %2 = [20, 2] + ? G.gen + %3 = [77, 51] + ? chi = [a, b] \\ maps g1 to e(a/20) and g2 to e(b/2); e(x) = exp(2ipi x) + @eprog\noindent + More generally, let $(\Z/N\Z)^{*} = \oplus (\Z/d_{j}\Z) g_{j}$ be given via a + \var{znstar} structure $G$ (\kbd{G.cyc} gives the $d_{j}$ and \kbd{G.gen} the + $g_{j}$). A \tev{character} $\chi$ on $G$ is given by a row vector + $v = [a_{1},\ldots,a_{n}]$ such that $\chi(\prod_{j} g_{j}^{n_{j}}) + = \exp(2\pi i\sum_{j} a_{j} n_{j} / d_{j})$. The pair $[G, v]$ encodes the + \emph{primitive} character attached to $\chi$. + + \item in fact, this construction $[G, m]$ describing a character + is more general: $m$ is also allowed to be a Conrey label as seen above, + or a Conrey logarithm (see \tet{znconreylog}), and the latter format is + actually the fastest one. Instead + of a single character as above, one may use the construction + \kbd{lfuncreate([G, vchi])} where \kbd{vchi} is a nonempty vector of + characters \emph{of the same conductor} (more precisely, whose attached + primitive characters have the same conductor) and \emph{same parity}. + The function is then vector-valued, where the values are ordered as the + characters in \kbd{vchi}. Conrey labels cannot be used in this last format + because of the need to distinguish a single character given by a row vector + of integers and a vector of characters given by their labels: use + \kbd{znconreylog(G,i)} first to convert a label to Conrey logarithm. + + \item it is also possible to view Dirichlet characters as Hecke characters + over $K = \Q$ (see below), for a modulus $[N, [1]]$ but this is both more + complicated and less efficient. + + In all cases, a nonprimitive character is replaced by the attached primitive + character. + + \subsec{Hecke $L$-functions of finite order characters} %GPHELPskip + + The Dedekind zeta function of a number field $K = \Q[X]/(T)$ is encoded + either by the defining polynomial $T$, or any absolute number fields + structure (a \var{nf} is enough). + + An alternative description for the Dedekind zeta function of an Abelian + extension of a number field is to use class-field theory parameters + $[\var{bnr}, \var{subg}]$, see \kbd{bnrinit}. + \bprog + ? bnf = bnfinit(a^2 - a - 9); + ? bnr = bnrinit(bnf, [2, [0,0]]); subg = Mat(3); + ? L = lfuncreate([bnr, subg]); + @eprog + + Let $K$ be a number field given as a \kbd{bnfinit}. + Given a finite order Hecke character $\chi: Cl_{f}(K)\to \C$, we let + $$L(\chi, s) = \sum_{A \subset O_{K}} \chi(A)\, \left(N_{K/\Q}A\right)^{-s}.$$ + + Let $Cl_{f}(K) = \oplus (\Z/d_{j}\Z) g_{j}$ given by a \var{bnr} structure + with generators: the $d_{j}$ are given by \kbd{K.cyc} and the $g_{j}$ by + \kbd{K.gen}. + A \tev{character} $\chi$ on the ray class group is given by a row vector + $v = [a_{1},\ldots,a_{n}]$ such that $\chi(\prod_{j} g_{j}^{n_{j}}) + = \exp(2\pi i\sum_{j} a_{j} n_{j} / d_{j})$. The pair $[\var{bnr}, v]$ + encodes the \emph{primitive} character attached to $\chi$. + + \bprog + ? K = bnfinit(x^2-60); + ? Cf = bnrinit(K, [7, [1,1]], 1); \\ f = 7 oo_1 oo_2 + ? Cf.cyc + %3 = [6, 2, 2] + ? Cf.gen + %4 = [[2, 1; 0, 1], [22, 9; 0, 1], [-6, 7]~] + ? lfuncreate([Cf, [1,0,0]]); \\@com $\chi(g_{1}) = \zeta_{6}$, $\chi(g_{2})=\chi(g_{3})=1$ + @eprog + + \noindent Dirichlet characters on $(\Z/N\Z)^{*}$ are a special case, + where $K = \Q$: + \bprog + ? Q = bnfinit(x); + ? Cf = bnrinit(Q, [100, [1]]); \\ for odd characters on (Z/100Z)* + @eprog\noindent + For even characters, replace by \kbd{bnrinit(K, N)}. Note that the simpler + direct construction in the previous section will be more efficient. Instead + of a single character as above, one may use the construction + \kbd{lfuncreate([Cf, vchi])} where \kbd{vchi} is a nonempty vector of + characters \emph{of the same conductor} (more precisely, whose attached + primitive characters have the same conductor). The function is then + vector-valued, where the values are ordered as the characters in \kbd{vchi}. + + \subsec{General Hecke $L$-functions} \label{se:lfungchar} %GPHELPskip + + Given a Hecke \tev{Grossencharacter} $\chi: \A^{\times}\to \C^{\times}$ of + conductor~$\goth{f}$, we let + $$L(\chi, s) = \sum_{A \subset \Z_{K},\ A+\goth{f}=\Z_{K}} \chi(A)\, \left(N_{K/\Q}A\right)^{-s}.$$ + + Let $C_{K}(\goth{m})=\A^{\times}/(K^{\times}\cdot U(\goth{m}))$ be an id\`ele class + group of modulus $\goth{m}$ given by a \var{gchar} structure~\var{gc} (see + \tet{gcharinit} and Section~\ref{se:GCHAR}). + A Grossencharacter $\chi$ on $C_{K}(\goth{m})$ is given by a row + vector of size \kbd{\#\var{gc}.cyc}. + + \bprog + ? gc = gcharinit(x^3+4*x-1,[5,[1]]); \\ mod = 5.oo + ? gc.cyc + %3 = [4, 2, 0, 0] + ? gcharlog(gc,idealprimedec(gc.bnf,5)[1]) \\@com logarithm map $C_{K}(\goth{m})\to \R^{n}$ + ? chi = [1,0,0,1,0]~; + ? gcharduallog(gc,chi) \\@com row vector of coefficients in $\R^{n}$ + ? L = lfuncreate([gc,chi]); \\@com non algebraic $L$-function + ? lfunzeros(L,1) + ? lfuneuler(L,2) \\@com Euler factor at 2 + @eprog + + Finite order Hecke characters are a special case. + + \subsec{Artin $L$ functions} %GPHELPskip + + Given a Galois number field $N/\Q$ with group $G = \kbd{galoisinit}(N)$, + a representation $\rho$ of $G$ over the cyclotomic field $\Q(\zeta_{n})$ + is specified by the matrices giving the images of $\kbd{G.gen}$ by $\rho$. + The corresponding Artin $L$ function is created using \tet{lfunartin}. + \bprog + P = quadhilbert(-47); \\ degree 5, Galois group D_5 + N = nfinit(nfsplitting(P)); \\ Galois closure + G = galoisinit(N); + [s,t] = G.gen; \\ order 5 and 2 + L = lfunartin(N,G, [[a,0;0,a^-1],[0,1;1,0]], 5); \\ irr. degree 2 + @eprog\noindent In the above, the polynomial variable (here \kbd{a}) represents + $\zeta_{5} := \exp(2i\pi/5)$ and the two matrices give the images of + $s$ and $t$. Here, priority of \kbd{a} must be lower than the priority + of \kbd{x}. + + \subsec{$L$-functions of algebraic varieties} %GPHELPskip + + $L$-function of elliptic curves over number fields are supported. + \bprog + ? E = ellinit([1,1]); + ? L = lfuncreate(E); \\ L-function of E/Q + ? E2 = ellinit([1,a], nfinit(a^2-2)); + ? L2 = lfuncreate(E2); \\ L-function of E/Q(sqrt(2)) + @eprog + + $L$-function of hyperelliptic genus-$2$ curve can be created with + \kbd{lfungenus2}. To create the $L$ function of the curve + $y^{2}+(x^{3}+x^{2}+1)y = x^{2}+x$: + \bprog + ? L = lfungenus2([x^2+x, x^3+x^2+1]); + @eprog + Currently, the model needs to be minimal at $2$, and if the conductor is even, + its valuation at $2$ might be incorrect (a warning is issued). + + \subsec{Eta quotients / Modular forms} %GPHELPskip + + An eta quotient is created by applying \tet{lfunetaquo} to a matrix with + 2 columns $[m, r_{m}]$ representing + $$ f(\tau) := \prod_{m} \eta(m\tau)^{r_{m}}. $$ + It is currently assumed that $f$ is a self-dual cuspidal form on + $\Gamma_{0}(N)$ for some $N$. + For instance, the $L$-function $\sum \tau(n) n^{-s}$ + attached to Ramanujan's $\Delta$ function is encoded as follows + \bprog + ? L = lfunetaquo(Mat([1,24])); + ? lfunan(L, 100) \\ first 100 values of tau(n) + @eprog + + More general modular forms defined by modular symbols will be added later. + + \subsec{Low-level Ldata format} %GPHELPskip + + When no direct constructor is available, you can still input an $L$ function + directly by supplying $[a, a^{*},A, k, N, \epsilon, r]$ to \kbd{lfuncreate} + (see \kbd{??lfuncreate} for details). + + It is \emph{strongly} suggested to first check consistency of the created + $L$-function: + \bprog + ? L = lfuncreate([a, as, A, k, N, eps, r]); + ? lfuncheckfeq(L) \\ check functional equation + @eprog + +Function: _header_linear_algebra +Class: header +Section: linear_algebra +Doc: + \section{Vectors, matrices, linear algebra and sets} + \label{se:linear_algebra} + + Note that most linear algebra functions operating on subspaces defined by + generating sets (such as \tet{mathnf}, \tet{qflll}, etc.) take matrices as + arguments. As usual, the generating vectors are taken to be the + \emph{columns} of the given matrix. + + Since PARI does not have a strong typing system, scalars live in + unspecified commutative base rings. It is very difficult to write + robust linear algebra routines in such a general setting. We thus + assume that the base ring is a domain and work over its field of + fractions. If the base ring is \emph{not} a domain, one gets an error as soon + as a nonzero pivot turns out to be noninvertible. Some functions, + e.g.~\kbd{mathnf} or \kbd{mathnfmod}, specifically assume that the base ring is + $\Z$. + +Function: _header_modular_forms +Class: header +Section: modular_forms +Doc: + \section{Modular forms} + + This section describes routines for working with modular forms and modular + form spaces. + + \subsec{Modular form spaces} %GPHELPskip + + These structures are initialized by the \kbd{mfinit} command; supported + modular form \emph{spaces} with corresponding flags are the following: + + \item The full modular form space $M_{k}(\Gamma_{0}(N),\chi)$, where $k$ is an + integer or a half-integer and $\chi$ a Dirichlet character modulo $N$ + ($\fl=4$, the default). + + \item The cuspidal space $S_{k}(\Gamma_{0}(N),\chi)$ ($\fl=1$). + + \item The Eisenstein space ${\cal E}_{k}(\Gamma_{0}(N),\chi)$ ($\fl=3$), so + that $M_{k}={\cal E}_{k}\oplus S_{k}$. + + \item The new space $S_{k}^{\text{new}}(\Gamma_{0}(N),\chi)$ ($\fl=0$). + + \item The old space $S_{k}^{\text{old}}(\Gamma_{0}(N),\chi)$ ($\fl=2$), + so that + $S_{k}=S_{k}^{\text{new}}\oplus S_{k}^{\text{old}}$. + + These resulting \kbd{mf} structure contains a basis of modular forms, which + is accessed by the function \kbd{mfbasis}; the elements of this basis have + Fourier coefficients in the cyclotomic field $\Q(\chi)$. These coefficients + are given algebraically, as rational numbers or \typ{POLMOD}s. The member + function \kbd{mf.mod} recovers the modulus used to define $\Q(\chi)$, which + is a cyclotomic polynomial $\Phi_{n}(t)$. When needed, the elements of + $\Q(\chi)$ are considered to be canonically embedded into $\C$ via + $\kbd{Mod}(t,\Phi_{n}(t)) \mapsto \exp(2i\pi/n)$. + + The basis of eigenforms for the new space is obtained by the function + \kbd{mfeigenbasis}: the elements of this basis now have Fourier coefficients + in a relative field extension of $\Q(\chi)$. Note that if the space is + larger than the new space (i.e. is the cuspidal or full space) we + nevertheless obtain only the eigenbasis for the new space. + + \subsec{Generalized modular forms} %GPHELPskip + + A modular form is represented in a special internal format giving the + possibility to compute an arbitrary number of terms of its Fourier coefficients + at infinity $[a(0),a(1),...,a(n)]$ using the function \kbd{mfcoefs}. These + coefficients are given algebraically, as rational numbers or \typ{POLMOD}s. + The member function \kbd{f.mod} recovers the modulus used in the + coefficients of $f$, which will be the same as for $k = \Q(\chi)$ (a cyclotomic + polynomial), or define a number field extension $K/k$. + + Modular forms are obtained either directly from other mathematical objects, + e.g., elliptic curves, or by a specific formula, e.g., Eisenstein series or + Ramanujan's Delta function, or by applying standard operators to existing forms + (Hecke operators, Rankin--Cohen brackets, \dots). A function \kbd{mfparams} is + provided so that one can recover the level, weight, character and field of + definition corresponding to a given modular form. + + A number of creation functions and operations are provided. It is however + important to note that strictly speaking some of these operations create + objects which are \emph{not} modular forms: typical examples are + derivation or integration of modular forms, the Eisenstein series $E_{2}$, eta + quotients, or quotients of modular forms. These objects are nonetheless very + important in the theory, so are not considered as errors; however the user must + be aware that no attempt is made to check that the objects that he handles are + really modular. When the documentation of a function does not state that it + applies to generalized modular forms, then the output is undefined if the + input is not a true modular form. + +Function: _header_modular_symbols +Class: header +Section: modular_symbols +Doc: + \section{Modular symbols} + + Let $\Delta_{0} := \text{Div}^{0}(\P^{1}(\Q))$ be the abelian group of + divisors of degree $0$ on the rational projective line. The standard + $\text{GL}(2,\Q)$ action on $\P^{1}(\Q)$ via homographies naturally extends to + $\Delta_{0}$. Given + + \item $G$ a finite index subgroup of $\text{SL}(2,\Z)$, + + \item a field $F$ and a finite dimensional representation $V/F$ of + $\text{GL}(2,\Q)$, + + \noindent we consider the space of \emph{modular symbols} $M := + \Hom_{G}(\Delta_{0}, V)$. This finite dimensional $F$-vector + space is a $G$-module, canonically isomorphic to $H^{1}_{c}(X(G), V)$, + and allows to compute modular forms for $G$. + + Currently, we only support the groups $\Gamma_{0}(N)$ ($N > 0$ an integer) + and the representations $V_{k} = \Q[X,Y]_{k-2}$ ($k \geq 2$ an integer) over + $\Q$. We represent a space of modular symbols by an \var{ms} structure, + created by the function \tet{msinit}. It encodes basic data attached to the + space: chosen $\Z[G]$-generators $(g_{i})$ for $\Delta_{0}$ + (and relations among + those) and an $F$-basis of $M$. A modular symbol $s$ is thus given either in + terms of this fixed basis, or as a collection of values $s(g_{i})$ + satisfying certain relations. + + A subspace of $M$ (e.g. the cuspidal or Eisenstein subspaces, the new or + old modular symbols, etc.) is given by a structure allowing quick projection + and restriction of linear operators; its first component is a matrix whose + columns form an $F$-basis of the subspace. + +Function: _header_number_fields +Class: header +Section: number_fields +Doc: + \section{General number fields} + + In this section, we describe functions related to general number fields. + Functions related to quadratic number fields are found in + \secref{se:arithmetic} (Arithmetic functions). + + \subsec{Number field structures} %GPHELPskip + + Let $K = \Q[X] / (T)$ a number field, $\Z_{K}$ its ring of integers, + $T\in\Z[X]$ + is monic. Three basic number field structures can be attached to $K$ in + GP: + + \item $\tev{nf}$ denotes a number field, i.e.~a data structure output by + \tet{nfinit}. This contains the basic arithmetic data attached to the + number field: signature, maximal order (given by a basis \kbd{nf.zk}), + discriminant, defining polynomial $T$, etc. + + \item $\tev{bnf}$ denotes a ``Buchmann's number field'', i.e.~a + data structure output by \tet{bnfinit}. This contains + $\var{nf}$ and the deeper invariants of the field: units $U(K)$, class group + $\Cl(K)$, as well as technical data required to solve the two attached + discrete logarithm problems. + + \item $\tev{bnr}$ denotes a ``ray number field'', i.e.~a data structure + output by \kbd{bnrinit}, corresponding to the ray class group structure of + the field, for some modulus $f$. It contains a \var{bnf}, the modulus + $f$, the ray class group $\Cl_{f}(K)$ and data attached to + the discrete logarithm problem therein. + + \subsec{Algebraic numbers and ideals} %GPHELPskip + + \noindent An \tev{algebraic number} belonging to $K = \Q[X]/(T)$ is given as + + \item a \typ{INT}, \typ{FRAC} or \typ{POL} (implicitly modulo $T$), or + + \item a \typ{POLMOD} (modulo $T$), or + + \item a \typ{COL}~\kbd{v} of dimension $N = [K:\Q]$, representing + the element in terms of the computed integral basis, as + \kbd{sum(i = 1, N,~v[i] * nf.zk[i])}. Note that a \typ{VEC} + will not be recognized. + \medskip + + \noindent An \tev{ideal} is given in any of the following ways: + + \item an algebraic number in one of the above forms, defining a principal ideal. + + \item a prime ideal, i.e.~a 5-component vector in the format output by + \kbd{idealprimedec} or \kbd{idealfactor}. + + \item a \typ{MAT}, square and in Hermite Normal Form (or at least + upper triangular with nonnegative coefficients), whose columns represent a + $\Z$-basis of the ideal. + + One may use \kbd{idealhnf} to convert any ideal to the last (preferred) format. + + \item an \emph{extended ideal} \sidx{ideal (extended)} is a 2-component + vector $[I, t]$, where $I$ is an ideal as above and $t$ is an algebraic + number, representing the ideal $(t)I$. This is useful whenever \tet{idealred} + is involved, implicitly working in the ideal class group, while keeping track + of principal ideals. The following multiplicative ideal operations + update the principal part: \kbd{idealmul}, \kbd{idealinv}, + \kbd{idealsqr}, \kbd{idealpow} and \kbd{idealred}; e.g.~using \kbd{idealmul} + on $[I,t]$, $[J,u]$, we obtain $[IJ, tu]$. In all other + functions, the extended part is silently discarded, e.g.~using + \kbd{idealadd} with the above input produces $I+J$. + + The ``principal part'' $t$ in an extended ideal may be + represented in any of the above forms, and \emph{also} as a factorization + matrix (in terms of number field elements, not ideals!), possibly the empty + factorization matrix \kbd{factor(1)} representing $1$; the empty matrix + \kbd{[;]} is also accepted as a synonym for $1$. When $t$ is such a + factorization matrix, elements stay in + factored form, or \tev{famat} for \emph{fa}ctorization \emph{mat}rix, which + is a convenient way to avoid coefficient explosion. To recover the + conventional expanded form, try \tet{nffactorback}; but many functions + already accept \var{famat}s as input, for instance \tet{ideallog}, so + expanding huge elements should never be necessary. + + \subsec{Finite abelian groups} %GPHELPskip + + A finite abelian group $G$ in user-readable format is given by its Smith + Normal Form as a pair $[h,d]$ or triple $[h,d,g]$. + Here $h$ is the cardinality of $G$, $(d_{i})$ is the vector of elementary + divisors, and $(g_{i})$ is a vector of generators. In short, + $G = \oplus_{i\leq n} (\Z/d_{i}\Z) g_{i}$, with + $d_{n} \mid \dots \mid d_{2} \mid d_{1}$ + and $\prod_{i} d_{i} = h$. This information can also be retrieved as + $G.\kbd{no}$, $G.\kbd{cyc}$ and $G.\kbd{gen}$. + + \item a \tev{character} on the abelian group $\oplus (\Z/d_{j}\Z) g_{j}$ + is given by a row vector $\chi = [a_{1},\ldots,a_{n}]$ such that + $\chi(\prod_{j} g_{j}^{n_{j}}) = \exp(2\pi i\sum_{j} a_{j} n_{j} / d_{j})$. + + \item given such a structure, a \tev{subgroup} $H$ is input as a square + matrix in HNF, whose columns express generators of $H$ on the given generators + $g_{i}$. Note that the determinant of that matrix is equal to the index $(G:H)$. + + \subsec{Relative extensions} %GPHELPskip + + We now have a look at data structures attached to relative extensions + of number fields $L/K$, and to projective $\Z_{K}$-modules. When defining a + relative extension $L/K$, the $\var{nf}$ attached to the base field $K$ + must be defined by a variable having a lower priority (see + \secref{se:priority}) than the variable defining the extension. For example, + you may use the variable name $y$ to define the base field $K$, and $x$ to + define the relative extension $L/K$. + + \misctitle{Basic definitions}\label{se:ZKmodules} %GPHELPskip + + \item $\tev{rnf}$ denotes a relative number field, i.e.~a data structure + output by \kbd{rnfinit}, attached to the extension $L/K$. The \var{nf} + attached to be base field $K$ is \kbd{rnf.nf}. + + \item A \emph{relative matrix} is an $m\times n$ matrix whose entries are + elements of $K$, in any form. Its $m$ columns $A_{j}$ represent elements + in $K^{n}$. + + \item An \tev{ideal list} is a row vector of fractional ideals of the number + field $\var{nf}$. + + \item A \tev{pseudo-matrix} is a 2-component row vector $(A,I)$ where $A$ + is a relative $m\times n$ matrix and $I$ an ideal list of length $n$. If $I = + \{\goth{a}_{1},\dots, \goth{a}_{n}\}$ and the columns of $A$ are $(A_{1},\dots, + A_{n})$, this data defines the torsion-free (projective) $\Z_{K}$-module + $\goth{a}_{1} A_{1}\oplus \goth{a}_{n} A_{n}$. + + \item An \tev{integral pseudo-matrix} is a 3-component row vector $(A,I,J)$ + where $A = (a_{i,j})$ is an $m\times n$ relative matrix and $I = + (\goth{b}_{1},\dots, \goth{b}_{m})$, $J = (\goth{a}_{1},\dots, \goth{a}_{n})$ are ideal + lists, such that $a_{i,j} \in \goth{b}_{i} \goth{a}_{j}^{-1}$ for all $i,j$. This + data defines two abstract projective $\Z_{K}$-modules + $N = \goth{a}_{1}\omega_{1}\oplus \cdots\oplus \goth{a}_{n}\omega_{n}$ + in $K^{n}$, + $P = \goth{b}_{1}\eta_{1}\oplus \cdots\oplus \goth{b}_{m}\eta_{m}$ in $K^{m}$, + and a $\Z_{K}$-linear map $f:N\to P$ given by + $$ f(\sum_{j} \alpha_{j}\omega_{j}) = \sum_{i} \Big(a_{i,j}\alpha_{j}\Big) + \eta_{i}.$$ + This data defines the $\Z_{K}$-module $M = P/f(N)$. + + \item Any \emph{projective} $\Z_{K}$-module\varsidx{projective module} $M$ + of finite type in $K^{m}$ can be given by a pseudo matrix $(A,I)$. + + \item An arbitrary $\Z_{K}$ module of finite type in $K^{m}$, with nontrivial + torsion, is given by an integral pseudo-matrix $(A,I,J)$ + + \misctitle{Algebraic numbers in relative extension} + + We are given a number field $K = \kbd{nfinit}(T)$, attached to $K = \Q[Y]/(T)$, + $T \in \Q[Y]$, and a relative extension $L = \kbd{rnfinit}(K, P)$, attached + to $L = K[X]/(P)$, $P \in K[X]$. + In all contexts (except \kbd{rnfeltabstorel} and \kbd{rnfeltdown}, see below), an + \tev{algebraic number} is given as + + \item a \typ{INT}, \typ{FRAC} or \typ{POL} in $\Q[Y]$ (implicitly modulo $T$) + or a \typ{POL} in $K[X]$ (implicitly modulo $P$), + + \item a \typ{POLMOD} (modulo $T$ or $P$), or + + \item a \typ{COL}~\kbd{v} of dimension $m = [K:\Q]$, representing + the element in terms of the integral basis \kbd{K.zk}; + + \item if an absolute \kbd{nf} structure \kbd{Labs} was attached to $L$, via + \kbd{Labs = nfinit}$(L)$, then we can also use a \typ{COL}~\kbd{v} of + dimension $[L:\Q]$, representing the element in terms of the computed integral + basis \kbd{Labs.zk}. Be careful that in the degenerate case + $L = K$, then the previous interpretation (with respect to \kbd{$K$.zk}) + takes precedence. This is no concern when $K = \Q$ or if $P = X - Y$ + (because in that case the primitive + polynomial \kbd{Labs.pol} defining $L$ of $\Q$ is \kbd{nf.pol} and the + computation of \kbd{nf.zk} is deterministic); but in other cases, the + integer bases attached to $K$ and \kbd{Labs} may differ. + + \misctitle{Special case: \kbd{rnfeltabstorel} and \kbd{rnfeltdown}} + These two functions assume + that elements are given in absolute representation (with respect to + \kbd{Labs.zk} or modulo \kbd{Labs.pol} and converts them to relative + representation modulo \kbd{$L$.pol}. In these two functions (only), a \typ{POL} in + $X$ is implicitly understood modulo \kbd{Labs.pol} and a \typ{COL} + of length $[L:\Q]$ refers to the integral basis \kbd{Labs.zk} in all cases, + including $L = K$. + + \misctitle{Pseudo-bases, determinant} %GPHELPskip + + \item The pair $(A,I)$ is a \tev{pseudo-basis} of the module it + generates if the $\goth{a}_{j}$ are nonzero, and the $A_{j}$ are $K$-linearly + independent. We call $n$ the \emph{size} of the pseudo-basis. If $A$ is a + relative matrix, the latter condition means it is square with nonzero + determinant; we say that it is in Hermite Normal + Form\sidx{Hermite normal form} (HNF) if it is upper triangular and all the + elements of the diagonal are equal to 1. + + \item For instance, the relative integer basis \kbd{rnf.zk} is a pseudo-basis + $(A,I)$ of $\Z_{L}$, where $A = \kbd{rnf.zk[1]}$ is a vector of elements of $L$, + which are $K$-linearly independent. Most \var{rnf} routines return and handle + $\Z_{K}$-modules contained in $L$ (e.g.~$\Z_{L}$-ideals) via a pseudo-basis + $(A',I')$, where $A'$ is a relative matrix representing a vector of elements of + $L$ in terms of the fixed basis \kbd{rnf.zk[1]} + + \item The \emph{determinant} of a pseudo-basis $(A,I)$ is the ideal + equal to the product of the determinant of $A$ by all the ideals of $I$. The + determinant of a pseudo-matrix is the determinant of any pseudo-basis of the + module it generates. + + \subsec{Class field theory}\label{se:CFT} + + A $\tev{modulus}$, in the sense of class field theory, is a divisor supported + on the real and finite places of $K$. In PARI terms, this means either an + ordinary ideal $I$ as above (no Archimedean component), or a pair $[I,a]$, + where $a$ is a vector with $r_{1}$ $\{0,1\}$-components, corresponding to the + infinite part of the divisor. More precisely, the $i$-th component of $a$ + corresponds to the real embedding attached to the $i$-th real root of + \kbd{K.roots}. (That ordering is not canonical, but well defined once a + defining polynomial for $K$ is chosen.) For instance, \kbd{[1, [1,1]]} is a + modulus for a real quadratic field, allowing ramification at any of the two + places at infinity, and nowhere else. + + A \tev{bid} or ``big ideal'' is a structure output by \kbd{idealstar} + needed to compute in $(\Z_{K}/I)^{*}$, where $I$ is a modulus in the above sense. + It is a finite abelian group as described above, supplemented by + technical data needed to solve discrete log problems. + + Finally we explain how to input ray number fields (or \var{bnr}), using class + field theory. These are defined by a triple $A$, $B$, $C$, where the + defining set $[A,B,C]$ can have any of the following forms: + $[\var{bnr}]$, + $[\var{bnr},\var{subgroup}]$, + $[\var{bnr},\var{character}]$, + $[\var{bnf},\var{mod}]$, + $[\var{bnf},\var{mod},\var{subgroup}]$. The last two forms are kept for + backward compatibility, but no longer serve any real purpose (see example + below); no newly written function will accept them. + + \item $\var{bnf}$ is as output by \kbd{bnfinit}, where units are mandatory + unless the modulus is trivial; \var{bnr} is as output by \kbd{bnrinit}. This + is the ground field $K$. + + \item \emph{mod} is a modulus $\goth{f}$, as described above. + + \item \emph{subgroup} a subgroup of the ray class group modulo $\goth{f}$ of + $K$. As described above, this is input as a square matrix expressing + generators of a subgroup of the ray class group \kbd{\var{bnr}.clgp} on the + given generators. We also allow a \typ{INT} $n$ for $n \cdot \text{Cl}_{f}$. + + \item \emph{character} is a character $\chi$ of the ray class group modulo + $\goth{f}$, representing the subgroup $\text{Ker} \chi$. + + The corresponding \var{bnr} is the subfield of the ray class field of $K$ + modulo $\goth{f}$, fixed by the given subgroup. + + \bprog + ? K = bnfinit(y^2+1); + ? bnr = bnrinit(K, 13) + ? %.clgp + %3 = [36, [12, 3]] + ? bnrdisc(bnr); \\ discriminant of the full ray class field + ? bnrdisc(bnr, [3,1;0,1]); \\ discriminant of cyclic cubic extension of K + ? bnrconductor(bnr, [3,1]); \\ conductor of chi: g1->zeta_12^3, g2->zeta_3 + @eprog\noindent + We could have written directly + \bprog + ? bnrdisc(K, 13); + ? bnrdisc(K, 13, [3,1;0,1]); + @eprog\noindent + avoiding one \tet{bnrinit}, but this would actually be slower since the + \kbd{bnrinit} is called internally anyway. And now twice! + + \subsec{General use} + + All the functions which are specific to relative extensions, number fields, + Buchmann's number fields, Buchmann's number rays, share the prefix \kbd{rnf}, + \kbd{nf}, \kbd{bnf}, \kbd{bnr} respectively. They take as first argument a + number field of that precise type, respectively output by \kbd{rnfinit}, + \kbd{nfinit}, \kbd{bnfinit}, and \kbd{bnrinit}. + + However, and even though it may not be specified in the descriptions of the + functions below, it is permissible, if the function expects a $\var{nf}$, to + use a $\var{bnf}$ instead, which contains much more information. On the other + hand, if the function requires a \kbd{bnf}, it will \emph{not} launch + \kbd{bnfinit} for you, which is a costly operation. Instead, it will give you + a specific error message. In short, the types + $$ \kbd{nf} \leq \kbd{bnf} \leq \kbd{bnr}$$ + are ordered, each function requires a minimal type to work properly, but you + may always substitute a larger type. + + The data types corresponding to the structures described above are rather + complicated. Thus, as we already have seen it with elliptic curves, GP + provides ``member functions'' to retrieve data from these structures (once + they have been initialized of course). The relevant types of number fields + are indicated between parentheses: \smallskip + + \sidx{member functions} + \settabs\+xxxxxxx&(\var{bnr},x&\var{bnf},x&nf\hskip2pt&)x&: &\cr + \+\tet{bid} &(\var{bnr}&&&)&: & bid ideal structure.\cr + + \+\tet{bnf} &(\var{bnr},& \var{bnf}&&)&: & Buchmann's number field.\cr + + \+\tet{clgp} &(\var{bnr},& \var{bnf}&&)&: & classgroup. This one admits the + following three subclasses:\cr + + \+ \quad \tet{cyc} &&&&&: & \quad cyclic decomposition + (SNF)\sidx{Smith normal form}.\cr + + \+ \quad \kbd{gen}\sidx{gen (member function)} &&&&&: & + \quad generators.\cr + + \+ \quad \tet{no} &&&&&: & \quad number of elements.\cr + + \+\tet{diff} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the different ideal.\cr + + \+\tet{codiff}&(\var{bnr},& \var{bnf},& \var{nf}&)&: & the codifferent + (inverse of the different in the ideal group).\cr + + \+\tet{disc} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & discriminant.\cr + + \+\tet{fu} &( & \var{bnf}&&)&: & \idx{fundamental units}.\cr + + \+\tet{index} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & + \idx{index} of the power order in the ring of integers.\cr + + \+\tet{mod} &(\var{bnr}&&&)&: & modulus.\cr + + \+\tet{nf} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & number field.\cr + + \+\tet{pol} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & defining polynomial.\cr + + \+\tet{r1} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the number + of real embeddings.\cr + + \+\tet{r2} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the number + of pairs of complex embeddings.\cr + + \+\tet{reg} &( & \var{bnf}&&)&: & regulator.\cr + + \+\tet{roots}&(\var{bnr},& \var{bnf},& \var{nf}&)&: & roots of the + polynomial generating the field.\cr + + \+\tet{sign} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & signature $[r1,r2]$.\cr + + \+\tet{t2} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & the $T_{2}$ matrix (see + \kbd{nfinit}).\cr + + \+\tet{tu} &( & \var{bnf}&&)&: & a generator for the torsion + units.\cr + + \+\tet{zk} &(\var{bnr},& \var{bnf},& \var{nf}&)&: & integral basis, i.e.~a + $\Z$-basis of the maximal order.\cr + + \+\tet{zkst} &(\var{bnr}&&&)&: & structure of $(\Z_{K}/m)^{*}$.\cr + + The member functions \kbd{.codiff}, \kbd{.t2} and \kbd{.zk} perform a + computation and are relatively expensive in large degree: move them out of + tight loops and store them in variables. + + For instance, assume that $\var{bnf} = \kbd{bnfinit}(\var{pol})$, for some + polynomial. Then \kbd{\var{bnf}.clgp} retrieves the class group, and + \kbd{\var{bnf}.clgp.no} the class number. If we had set $\var{bnf} = + \kbd{nfinit}(\var{pol})$, both would have output an error message. All these + functions are completely recursive, thus for instance + \kbd{\var{bnr}.bnf.nf.zk} will yield the maximal order of \var{bnr}, which + you could get directly with a simple \kbd{\var{bnr}.zk}. + + \subsec{Class group, units, and the GRH}\label{se:GRHbnf} + + Some of the functions starting with \kbd{bnf} are implementations of the + sub-exponential algorithms for finding class and unit groups under \idx{GRH}, + due to Hafner-McCurley, \idx{Buchmann} and Cohen-Diaz-Olivier. The general + call to the functions concerning class groups of general number fields + (i.e.~excluding \kbd{quadclassunit}) involves a polynomial $P$ and a + technical vector + $$\var{tech} = [c_{1}, c_{2}, \var{nrpid} ],$$ + where the parameters are to be understood as follows: + + $P$ is the defining polynomial for the number field, which must be in + $\Z[X]$, irreducible and monic. In fact, if you supply a nonmonic polynomial + at this point, \kbd{gp} issues a warning, then \emph{transforms your + polynomial} so that it becomes monic. The \kbd{nfinit} routine + will return a different result in this case: instead of \kbd{res}, you get a + vector \kbd{[res,Mod(a,Q)]}, where \kbd{Mod(a,Q) = Mod(X,P)} gives the change + of variables. In all other routines, the variable change is simply lost. + + The \var{tech} interface is obsolete and you should not tamper with + these parameters. Indeed, from version 2.4.0 on, + + \item the results are always rigorous under \idx{GRH} (before that version, + they relied on a heuristic strengthening, hence the need for overrides). + + \item the influence of these parameters on execution time and stack size is + marginal. They \emph{can} be useful to fine-tune and experiment with the + \kbd{bnfinit} code, but you will be better off modifying all tuning + parameters in the C code (there are many more than just those three). + We nevertheless describe it for completeness. + + The numbers $c_{1} \leq c_{2}$ are nonnegative real numbers. By default they + are chosen so that the result is correct under GRH. For $i = 1,2$, let + $B_{i} = c_{i}(\log |d_{K}|)^{2}$, and denote by $S(B)$ the set of maximal + ideals of $K$ whose norm is less than $B$. We want $S(B_{1})$ to generate + $\Cl(K)$ and hope that $S(B_{2})$ can be \emph{proven} to generate $\Cl(K)$. + + More precisely, $S(B_{1})$ is a factorbase used to compute a tentative + $\Cl(K)$ by generators and relations. We then check explicitly, using + essentially \kbd{bnfisprincipal}, that the elements of $S(B_{2})$ belong to the + span of $S(B_{1})$. Under the assumption that $S(B_{2})$ generates $\Cl(K)$, we + are done. User-supplied $c_{i}$ are only used to compute initial guesses for + the bounds $B_{i}$, and the algorithm increases them until one can \emph{prove} + under GRH that $S(B_{2})$ generates $\Cl(K)$. A uniform result of Greni\'e + and Molteni says + that $c_{2} = 4$ is always suitable, but this bound is very pessimistic and a + direct algorithm due to Belabas-Diaz-Friedman, improved by Greni\'e and + Molteni, is used to check the condition, assuming GRH. The default values + are $c_{1} = c_{2} = 0$. When $c_{1}$ is equal to $0$ the algorithm takes it + equal to $c_{2}$. + + $\var{nrpid}$ is the maximal number of small norm relations attached to each + ideal in the factor base. Set it to $0$ to disable the search for small norm + relations. Otherwise, reasonable values are between 4 and 20. The default is + 4. + + \misctitle{Warning} Make sure you understand the above! By default, most of + the \kbd{bnf} routines depend on the correctness of the GRH. In particular, + any of the class number, class group structure, class group generators, + regulator and fundamental units may be wrong, independently of each other. + Any result computed from such a \kbd{bnf} may be wrong. The only guarantee is + that the units given generate a subgroup of finite index in the full unit + group. You must use \kbd{bnfcertify} to certify the computations + unconditionally. + + \misctitle{Remarks} + + You do not need to supply the technical parameters (under the library you + still need to send at least an empty vector, coded as \kbd{NULL}). However, + should you choose to set some of them, they \emph{must} be given in the + requested order. For example, if you want to specify a given value of + \var{nrpid}, you must give some values as well for $c_{1}$ and $c_{2}$, + and provide a vector $[c_{1},c_{2},\var{nrpid}]$. + + Note also that you can use an $\var{nf}$ instead of $P$, which avoids + recomputing the integral basis and analogous quantities. + + \subsec{Hecke Grossencharacters}\label{se:GCHAR} + + Hecke Grossencharacters are continuous characters of the id\`ele class group; + they generalize classical Hecke characters on ray class groups obtained through + the $\var{bnr}$ structure. + + Let $K$ be a number field, $\A^{\times}$ its group of id\`eles. + Every Grossencharacter + $$ + \chi \colon \A^{\times}/K^{\times} \to \C^{\times} + $$ + can be uniquely written~$\chi = \chi_{0} \|\cdot \|^{s}$ for some~$s\in\C$ + and some character~$\chi_{0}$ of the compact + group~$\A^{\times}/(K^{\times}\cdot\R_{>0})$, + where~$\|a\| = \prod_{v} |a_{v}|_{v}$ is the id\`ele norm. + + Let~$\goth{m}$ be a modulus + (an integral ideal and a finite set of real places). Let $U(\goth{m})$ be the + subgroup of id\`eles congruent to $1$ modulo $\goth{m}$ + (units outside $\goth{m}$, positive at real places in $\goth{m}$). + The Hecke Grossencharacters defined modulo $\goth{m}$ are the characters of + the id\`ele class group + $$ + C_{K}(\goth{m}) = \A^{\times}/(K^{\times}\cdot U(\goth{m})), + $$ + that is, combinations of an archimedean + character $\chi_{\infty}$ on the connected component + $K_{\infty}^{\times \circ}$ + and a ray class group character $\chi_{f}$ satisfying a compatibility + condition $\chi_{\infty}(a)\chi_{f}(a)=1$ for all units $a$ congruent to 1 + modulo $\goth{m}$. + + \varsidx{gchar} % + \item \var{gc} denotes a structure allowing to compute with Hecke + Grossencharacters. + + \item \kbd{gcharinit(\var{bnf},\var{mod})} initializes the structure \var{gc}. + The underlying number field and modulus can be accessed using + \var{gc}\kbd{.bnf} and \var{gc}\kbd{.mod}. + + \item \var{gc}\kbd{.cyc} describes the finite abelian group structure of + \var{gc}, the torsion part corresponding to finite order ray class + characters, the exact zeros corresponding to a lattice of infinite order + Grossencharacters, and the approximate zero being a placeholder for the + complex powers of the id\`ele norm. + + \item A Hecke character of modulus~$\goth{m}$ is described as a \typ{COL} of + coordinates corresponding to~\var{gc}\kbd{.cyc}: all the coordinates are + integers except the last one, which can be an arbitrary complex number, or + omitted instead of~$0$. + + \item Hecke Grossencharacters have $L$-functions and can be given to all + \kbd{lfun} functions as a 2 components vector \kbd{[\var{gc},\var{chi}]}, see + also Section~\ref{se:lfungchar}. + +Function: _header_number_theoretical +Class: header +Section: number_theoretical +Doc: + \section{Arithmetic functions}\label{se:arithmetic} + + These functions are by definition functions whose natural domain of + definition is either $\Z$ (or $\Z_{>0}$). The way these functions are used is + completely different from transcendental functions in that there are no + automatic type conversions: in general only integers are accepted as + arguments. An integer argument $N$ can be given in the following alternate + formats: + + \item \typ{MAT}: its factorization \kbd{fa = factor($N$)}, + + \item \typ{VEC}: a pair \kbd{[$N$, fa]} giving both the integer and + its factorization. + + This allows to compute different arithmetic functions at a given $N$ + while factoring the latter only once. + + \bprog + ? N = 10!; faN = factor(N); + ? eulerphi(N) + %2 = 829440 + ? eulerphi(faN) + %3 = 829440 + ? eulerphi(S = [N, faN]) + %4 = 829440 + ? sigma(S) + %5 = 15334088 + @eprog + + \subsec{Arithmetic functions and the factoring engine} + All arithmetic functions in the narrow sense of the word~--- Euler's + totient\sidx{Euler totient function} function, the \idx{Moebius} function, + the sums over divisors or powers of divisors etc.--- call, after trial + division by small primes, the same versatile factoring machinery described + under \kbd{factorint}. It includes \idx{Shanks SQUFOF}, \idx{Pollard Rho}, + \idx{ECM} and \idx{MPQS} stages, and has an early exit option for the + functions \teb{moebius} and (the integer function underlying) + \teb{issquarefree}. This machinery relies on a fairly strong + probabilistic primality test, see \kbd{ispseudoprime}, but you may also set + \bprog + default(factor_proven, 1) + @eprog\noindent to ensure that all tentative factorizations are fully proven. + This should not slow down PARI too much, unless prime numbers with + hundreds of decimal digits occur frequently in your application. + + \subsec{Orders in finite groups and Discrete Logarithm functions} + \label{se:DLfun} + + The following functions compute the order of an element in a finite group: + \kbd{ellorder} (the rational points on an elliptic curve defined over a + finite field), \kbd{fforder} (the multiplicative group of a finite field), + \kbd{znorder} (the invertible elements in $\Z/n\Z$). The following functions + compute discrete logarithms in the same groups (whenever this is meaningful) + \kbd{elllog}, \kbd{fflog}, \kbd{znlog}. + + All such functions allow an optional argument specifying an integer + $N$, representing the order of the group. (The \emph{order} functions also + allows any nonzero multiple of the order, with a minor loss of efficiency.) + That optional argument follows the same format as given above: + + \item \typ{INT}: the integer $N$, + + \item \typ{MAT}: the factorization \kbd{fa = factor($N$)}, + + \item \typ{VEC}: this is the preferred format and provides both the + integer $N$ and its factorization in a two-component vector + \kbd{[$N$, fa]}. + + When the group is fixed and many orders or discrete logarithms will be + computed, it is much more efficient to initialize this data once + and pass it to the relevant functions, as in + \bprog + ? p = nextprime(10^30); + ? v = [p-1, factor(p-1)]; \\ data for discrete log & order computations + ? znorder(Mod(2,p), v) + %3 = 500000000000000000000000000028 + ? g = znprimroot(p); + ? znlog(2, g, v) + %5 = 543038070904014908801878611374 + @eprog + + \subsec{Dirichlet characters}\label{se:dirichletchar} + + The finite abelian group $G = (\Z/N\Z)^{*}$ can be written $G = \oplus_{i\leq + n} (\Z/d_{i}\Z) g_{i}$, with $d_{n} \mid \dots \mid d_{2} \mid d_{1}$ + (SNF condition), all $d_{i} > 0$, and $\prod_{i} d_{i} = \phi(N)$. + + The positivity and SNF condition make the $d_{i}$ unique, but the generators + $g_{i}$, of respective order $d_{i}$, are definitely not unique. The + $\oplus$ notation means that all elements of $G$ can be written uniquely as + $\prod_{i} g_{i}^{n_{i}}$ where $n_{i} \in \Z/d_{i}\Z$. The $g_{i}$ are the + so-called \tev{SNF generators} of $G$. + + \item a \tev{character} on the abelian group $\oplus_{j} (\Z/d_{j}\Z) g_{j}$ + is given by a row vector $\chi = [a_{1},\ldots,a_{n}]$ of integers + $0\leq a_{i} < d_{i}$ such that $\chi(g_{j}) = e(a_{j} / d_{j})$ for all $j$, + with the standard notation $e(x) := \exp(2i\pi x)$. + In other words, + $\chi(\prod_{j} g_{j}^{n_{j}}) = e(\sum_{j} a_{j} n_{j} / d_{j})$. + + This will be generalized to more general abelian groups in later sections + (Hecke characters), but in the present case of $(\Z/N\Z)^{*}$, there is a + useful + alternate convention : namely, it is not necessary to impose the SNF + condition and we can use Chinese remainders instead. If $N = \prod p^{e_{p}}$ + is + the factorization of $N$ into primes, the so-called \tev{Conrey generators} + of $G$ are the generators of the $(\Z/p^{e_{p}}\Z)^{*}$ lifted to + $(\Z/N\Z)^{*}$ by + requesting that they be congruent to $1$ modulo $N/p^{e_{p}}$ (for $p$ odd we + take the smallest positive primitive root mod $p^{2}$, and for $p = 2$ + we take $-1$ if + $e_{2} > 1$ and additionally $5$ if $e_{2} > 2$). We can again write $G = + \oplus_{i\leq n} (\Z/D_{i}\Z) G_{i}$, where again $\prod_{i} D_{i} = \phi(N)$. + These generators don't satisfy the SNF condition in general since their orders + are + now $(p-1)p^{e_{p}-1}$ for $p$ odd; for $p = 2$, the generator $-1$ has order + $2$ and $5$ has order $2^{e_{2}-2}$ $(e_{2} > 2)$. Nevertheless, any $m\in + (\Z/N\Z)^{*}$ can be uniquely decomposed as $m = \prod_{j} G_{i}^{m_{i}}$ + for some $m_{i}$ modulo $D_{i}$ and we can define a character by $\chi(G_{j}) + = e(m_{j} / D_{j})$ for all $j$. + + \item The \emph{column vector} of the $m_{j}$, $0 \leq m_{j} < D_{j}$ is + called the \tev{Conrey logarithm} of $m$ (discrete logarithm in terms of the + Conrey generators). Note that discrete logarithms in PARI/GP are always + expressed as \typ{COL}s. + + \item The attached character is called the \tev{Conrey character} + attached to $m$. + + To sum up a Dirichlet character can be defined by a \typ{INTMOD} + \kbd{Mod}$(m, N)$, a \typ{INT} lift (the Conrey label $m$), + a \typ{COL} (the Conrey logarithm of $m$, in terms of the Conrey + generators) or a \typ{VEC} (in terms of the SNF generators). The \typ{COL} + format, i.e. Conrey logarithms, is the preferred (fastest) representation. + + Concretely, this works as follows: + + \kbd{G = znstar(N, 1)} initializes $(\Z/N\Z)^{*}$, which must be given as + first arguments to all functions handling Dirichlet characters. + + \kbd{znconreychar} transforms \typ{INT}, \typ{INTMOD} and \typ{COL} to a SNF + character. + + \kbd{znconreylog} transforms \typ{INT}, \typ{INTMOD} and \typ{VEC} + to a Conrey logarithm. + + \kbd{znconreyexp} transforms \typ{VEC} and \typ{COL} to a Conrey label. + + Also available are \kbd{charconj}, \kbd{chardiv}, \kbd{charmul}, + \kbd{charker}, \kbd{chareval}, \kbd{charorder}, \kbd{zncharinduce}, + \kbd{znconreyconductor} (also computes the primitive character attached to + the input character). The prefix \kbd{char} indicates that the function + applies to all characters, the prefix \kbd{znchar} that it is specific to + Dirichlet characters (on $(\Z/N\Z)^{*}$) and the prefix \kbd{znconrey} that it + is specific to Conrey representation. + +Function: _header_operators +Class: header +Section: operators +Doc: + \section{Standard monadic or dyadic operators} + + \subsec{Boolean operators}\sidx{Boolean operators} + + Any nonzero value is interpreted as \var{true} and any zero as \var{false} + (this includes empty vectors or matrices). The standard boolean operators + \kbd{||} (\idx{inclusive or}), \kbd{\&\&} (\idx{and})\sidx{or} and \kbd{!} + in prefix notation (\idx{not}) are available. + Their value is $1$ (true) or $0$ (false): + \bprog + ? a && b \\ 1 iff a and b are nonzero + ? a || b \\ 1 iff a or b is nonzero + ? !a \\ 1 iff a is zero + @eprog + + \subsec{Comparison} + The standard real \idx{comparison operators} \kbd{<=}, \kbd{<}, \kbd{>=}, + \kbd{>}, are available in GP. The result is 1 if the comparison is true, 0 + if it is false. These operators allow to compare integers (\typ{INT}), + rational (\typ{FRAC}) or real (\typ{REAL}) numbers, + real quadratic numbers (\typ{QUAD} of positive discriminant) and infinity + (\kbd{oo}, \typ{INFINITY}). + + By extension, two character strings (\typ{STR}) are compared using + the standard lexicographic order. Comparing a string to an object of a + different type raises an exception. See also the \tet{cmp} universal + comparison function. + + \subsec{Equality} + Two operators allow to test for equality: \kbd{==} (equality up to type + coercion) and \kbd{===} (identity). The result is $1$ if equality is decided, + else $0$. + + The operator \kbd{===} is strict: objects of different type or length are + never identical, polynomials in different variables are never identical, + even if constant. On the contrary, \kbd{==} is very liberal: $a~\kbd{==}~b$ + decides whether there is a natural map sending $a$ to the domain of $b$ + or sending $b$ to the domain of $a$, such that the comparison makes sense + and equality holds. For instance + \bprog + ? 4 == Mod(1,3) \\ equal + %1 = 1 + ? 4 === Mod(1,3) \\ but not identical + %2 = 0 + + ? 'x == 'y \\ not equal (nonconstant and different variables) + %3 = 0 + ? Pol(0,'x) == Pol(0,'y) \\ equal (constant: ignore variable) + %4 = 1 + ? Pol(0,'x) === Pol(0,'y) \\ not identical + %5 = 0 + + ? 0 == Pol(0) \\ equal (not identical) + %6 = 1 + ? [0] == 0 \\ equal (not identical) + %7 = 1 + ? [0, 0] == 0 \\ equal (not identical) + %8 = 1 + ? [0] == [0,0] \\ not equal + %9 = 0 + @eprog\noindent In particular \kbd{==} is not transitive in general. The + operator \kbd{===} is transitive. The \kbd{==} operator allows two + equivalent negated forms: \kbd{!=} or \kbd{<>}; there is no negated form for + \kbd{===}. + + Do not mistake \kbd{=} for \kbd{==}: the former is the assignment statement. + + \subseckbd{+$/$-} The expressions \kbd{+}$x$ and \kbd{-}$x$ refer + to monadic operators: the first does nothing, the second negates $x$. + + The library syntax is \fun{GEN}{gneg}{GEN x} for \kbd{-}$x$. + + \subseckbd{+} The expression $x$ \kbd{+} $y$ is the \idx{sum} of $x$ and $y$. + Addition between a scalar type $x$ and a \typ{COL} or \typ{MAT} $y$ returns + respectively $[y[1] + x, y[2],\dots]$ and $y + x \text{Id}$. Other additions + between a scalar type and a vector or a matrix, or between vector/matrices of + incompatible sizes are forbidden. + + The library syntax is \fun{GEN}{gadd}{GEN x, GEN y}. + + \subseckbd{-} The expression $x$ \kbd{-} $y$ is the \idx{difference} of $x$ + and $y$. Subtraction between a scalar type $x$ and a \typ{COL} or \typ{MAT} + $y$ returns respectively $[y[1] - x, y[2],\dots]$ and $y - x \text{Id}$. + Other subtractions between a scalar type and a vector or a matrix, or + between vector/matrices of incompatible sizes are forbidden. + + The library syntax is \fun{GEN}{gsub}{GEN x, GEN y} for $x$ \kbd{-} $y$. + + \subseckbd{*} The expression $x$ \kbd{*} $y$ is the \idx{product} of $x$ + and $y$. Among the prominent impossibilities are multiplication between + vector/matrices of incompatible sizes, between a \typ{INTMOD} or \typ{PADIC}. + Restricted to scalars, \kbd{*} is commutative; because of vector and matrix + operations, it is not commutative in general. + + Multiplication between two \typ{VEC}s or two \typ{COL}s is not + allowed; to take the \idx{scalar product} of two vectors of the same length, + transpose one of the vectors (using the operator \kbd{\til} or the function + \kbd{mattranspose}, see \secref{se:linear_algebra}) and multiply a row vector + by a column vector: + \bprog + ? a = [1,2,3]; + ? a * a + *** at top-level: a*a + *** ^-- + *** _*_: forbidden multiplication t_VEC * t_VEC. + ? a * a~ + %2 = 14 + @eprog + + If $x,y$ are binary quadratic forms, compose them; see also + \kbd{qfbnucomp} and \kbd{qfbnupow}. If $x,y$ are \typ{VECSMALL} of the same + length, understand them as permutations and compose them. + + The library syntax is \fun{GEN}{gmul}{GEN x, GEN y} for $x$ \kbd{*} $y$. + Also available is \fun{GEN}{gsqr}{GEN x} for $x$ \kbd{*} $x$. + + \subseckbd{/} The expression $x$ \kbd{/} $y$ is the \idx{quotient} of $x$ + and $y$. In addition to the impossibilities for multiplication, note that if + the divisor is a matrix, it must be an invertible square matrix, and in that + case the result is $x*y^{-1}$. Furthermore note that the result is as exact + as possible: in particular, division of two integers always gives a rational + number (which may be an integer if the quotient is exact) and \emph{not} the + Euclidean quotient (see $x$ \kbd{\bs} $y$ for that), and similarly the + quotient of two polynomials is a rational function in general. To obtain the + approximate real value of the quotient of two integers, add \kbd{0.} to the + result; to obtain the approximate $p$-adic value of the quotient of two + integers, add \kbd{O(p\pow k)} to the result; finally, to obtain the + \idx{Taylor series} expansion of the quotient of two polynomials, add + \kbd{O(X\pow k)} to the result or use the \kbd{taylor} function + (see \secref{se:taylor}). \label{se:gdiv} + + The library syntax is \fun{GEN}{gdiv}{GEN x, GEN y} for $x$ \kbd{/} $y$. + + \subseckbd{\bs} The expression \kbd{$x$ \bs\ $y$} is the + \idx{Euclidean quotient} of $x$ and $y$. If $y$ is a real scalar, this is + defined as \kbd{floor($x$/$y$)} if $y > 0$, and \kbd{ceil($x$/$y$)} if + $y < 0$ and the division is not exact. Hence the remainder + \kbd{$x$ - ($x$\bs$y$)*$y$} is in $[0, |y|[$. + + Note that when $y$ is an integer and $x$ a polynomial, $y$ is first promoted + to a polynomial of degree $0$. When $x$ is a vector or matrix, the operator + is applied componentwise. + + The library syntax is \fun{GEN}{gdivent}{GEN x, GEN y} + for $x$ \kbd{\bs} $y$. + + \subseckbd{\bs/} The expression $x$ \b{/} $y$ evaluates to the rounded + \idx{Euclidean quotient} of $x$ and $y$. This is the same as \kbd{$x$ \bs\ $y$} + except for scalar division: the quotient is such that the corresponding + remainder is smallest in absolute value and in case of a tie the quotient + closest to $+\infty$ is chosen (hence the remainder would belong to + $[{-}|y|/2, |y|/2[$). + + When $x$ is a vector or matrix, the operator is applied componentwise. + + The library syntax is \fun{GEN}{gdivround}{GEN x, GEN y} + for $x$ \b{/} $y$. + + \subseckbd{\%} The expression \kbd{$x$ \% $y$} evaluates to the modular + \idx{Euclidean remainder} of $x$ and $y$, which we now define. When $x$ or $y$ + is a nonintegral real number, \kbd{$x$\%$y$} is defined as + \kbd{$x$ - ($x$\bs$y$)*$y$}. Otherwise, if $y$ is an integer, this is + the smallest + nonnegative integer congruent to $x$ modulo $y$. (This actually coincides + with the previous definition if and only if $x$ is an integer.) If $y$ is a + polynomial, this is the polynomial of smallest degree congruent to + $x$ modulo $y$. For instance: + \bprog + ? (1/2) % 3 + %1 = 2 + ? 0.5 % 3 + %2 = 0.5000000000000000000000000000 + ? (1/2) % 3.0 + %3 = 1/2 + @eprog + Note that when $y$ is an integer and $x$ a polynomial, $y$ is first promoted + to a polynomial of degree $0$. When $x$ is a vector or matrix, the operator + is applied componentwise. + + The library syntax is \fun{GEN}{gmod}{GEN x, GEN y} + for $x$ \kbd{\%} $y$. + + \subseckbd{!} The expression \kbd{$n!$} is the factorial of the + non-negative integer $n$. + + The library syntax is \fun{GEN}{mpfact}{long n} + + \subseckbd{\#} The expression \kbd{$n\#$} is the primorial of the + non-negative integer $n$, that is the product of all prime numbers less than + or equal to $x$. + + The library syntax is \fun{GEN}{mpprimorial}{long n} + + \subseckbd{op=} When \kbd{op} is a binary arithmetic operator among + \kbd{+}, \kbd{-}, \kbd{*}, \kbd{\%}, \kbd{/}, \kbd{\bs} or \kbd{\bs/}, the + construct $x$~\kbd{op=}~$y$ is a shortcut for $x$~\kbd{=}~$x\ \kbd{op}\ y$. + \bprog + ? v[1] += 10 \\ increment v[1] by 10 + ? a /= 2 \\ divide a by 2 + @eprog + + \subseckbd{++} \kbd{$x$++} is a shortcut for \kbd{$x$ = $x$ + 1} and for + \kbd{$x$ += 1}. + + \subseckbd{--} \kbd{$x$--} is a shortcut for \kbd{$x$ = $x$ - 1} and for + \kbd{$x$ -= 1}. + + \subseckbd{\pow} The expression $x\hbox{\kbd{\pow}}n$ is \idx{powering}. + + \item If the exponent $n$ is an integer, then exact operations are performed + using binary (left-shift) powering techniques. By definition, $x^{0}$ is + (an empty product interpreted as) an exact $1$ in the underlying prime + ring: + \bprog + ? 0.0 ^ 0 + %1 = 1 + ? (1 + O(2^3)) ^ 0 + %2 = 1 + ? (1 + O(x)) ^ 0 + %3 = 1 + ? Mod(2,4)^0 + %4 = Mod(1,4) + ? Mod(x,x^2)^0 + %5 = Mod(1, x^2) + @eprog\noindent + If $x$ is a $p$-adic number, its precision will increase if $v_{p}(n) > 0$ and + $n \neq 0$. Powering a binary quadratic form (type \typ{QFB}) returns a + representative of the class, which is reduced if the input was. + (In particular, \kbd{x \pow 1} returns $x$ itself, whether it is reduced or + not.) + + PARI rewrites the multiplication $x * x$ of two \emph{identical} + objects as $x^{2}$. Here, identical means the operands are reference the same + chunk of memory; no equality test is performed. This is no longer true when + more than two arguments are involved. + \bprog + ? a = 1 + O(2); b = a; + ? a * a \\ = a^2, precision increases + %2 = 1 + O(2^3) + ? a * b \\ not rewritten as a^2 + %3 = 1 + O(2) + ? a*a*a \\ not rewritten as a^3 + %4 = 1 + O(2) + @eprog + + \item If the exponent is a rational number $p/q$ the behaviour depends + on~$x$. If $x$ is a complex number, return $\exp(n \log x)$ (principal + branch), in an exact form if possible: + \bprog + ? 4^(1/2) \\ 4 being a square, this is exact + %1 = 2 + ? 2^(1/2) \\ now inexact + %2 = 1.4142135623730950488016887242096980786 + ? (-1/4)^(1/2) \\ exact again + %3 = 1/2*I + ? (-1)^(1/3) + %4 = 0.500...+ 0.866...*I + @eprog\noindent Note that even though $-1$ is an exact cube root of $-1$, + it is not $\exp(\log(-1)/3)$; the latter is returned. + + Otherwise return a solution $y$ of $y^{q} = x^{p}$ if it exists; beware that + this is defined up to $q$-th roots of 1 in the base field. Intmods modulo + composite numbers are not supported. + \bprog + ? Mod(7,19)^(1/2) + %1 = Mod(11, 19) \\ is any square root + ? sqrt(Mod(7,19)) + %2 = Mod(8, 19) \\ is the smallest square root + ? Mod(1,4)^(1/2) + *** at top-level: Mod(1,4)^(1/2) + *** ^------ + *** _^_: not a prime number in gpow: 4. + @eprog + + \item If the exponent is a negative integer or rational number, + an \idx{inverse} must be computed. For noninvertible \typ{INTMOD} $x$, this + will fail and (for $n$ an integer) implicitly exhibit a factor of the modulus: + \bprog + ? Mod(4,6)^(-1) + *** at top-level: Mod(4,6)^(-1) + *** ^----- + *** _^_: impossible inverse modulo: Mod(2, 6). + @eprog\noindent + Here, a factor 2 is obtained directly. In general, take the gcd of the + representative and the modulus. This is most useful when performing + complicated operations modulo an integer $N$ whose factorization is + unknown. Either the computation succeeds and all is well, or a factor $d$ + is discovered and the computation may be restarted modulo $d$ or $N/d$. + + For noninvertible \typ{POLMOD} $x$, the behavior is the same: + \bprog + ? Mod(x^2, x^3-x)^(-1) + *** at top-level: Mod(x^2,x^3-x)^(-1) + *** ^----- + *** _^_: impossible inverse in RgXQ_inv: Mod(x^2, x^3 - x). + @eprog\noindent Note that the underlying algorihm (subresultant) assumes + that the base ring is a domain: + \bprog + ? a = Mod(3*y^3+1, 4); b = y^6+y^5+y^4+y^3+y^2+y+1; c = Mod(a,b); + ? c^(-1) + *** at top-level: Mod(a,b)^(-1) + *** ^----- + *** _^_: impossible inverse modulo: Mod(2, 4). + @eprog\noindent + In fact $c$ is invertible, but $\Z/4\Z$ is not a domain and the algorithm + fails. It is possible for the algorithm to succeed in such situations + and any returned result will be correct, but chances are that an error + will occur first. In this specific case, one should work with $2$-adics. + In general, one can also try the following approach + \bprog + ? inversemod(a, b) = + { my(m, v = variable(b)); + m = polsylvestermatrix(polrecip(a), polrecip(b)); + m = matinverseimage(m, matid(#m)[,1]); + Polrev(m[1..poldegree(b)], v); + } + ? inversemod(a,b) + %2 = Mod(2,4)*y^5 + Mod(3,4)*y^3 + Mod(1,4)*y^2 + Mod(3,4)*y + Mod(2,4) + @eprog\noindent + This is not guaranteed to work either since \kbd{matinverseimage} must also + invert pivots. See \secref{se:linear_algebra}. + + For a \typ{MAT} $x$, the matrix is expected to be square and invertible, except + in the special case \kbd{x\pow(-1)} which returns a left inverse if one exists + (rectangular $x$ with full column rank). + \bprog + ? x = Mat([1;2]) + %1 = + [1] + + [2] + + ? x^(-1) + %2 = + [1 0] + @eprog + + \item Finally, if the exponent $n$ is not an rational number, powering is + treated as the transcendental function $\exp(n\log x)$, although it will be + more precise than the latter when $n$ and $x$ are exact: + \bprog + ? s = 1/2 + 10^14 * I + ? localprec(200); z = 2^s \\ for reference + ? exponent(2^s - z) + %3 = -127 \\ perfect + ? exponent(exp(s * log(2)) - z) + %4 = -84 \\ not so good + @eprog\noindent The second computation is less precise because $\log(2)$ is + first computed to $38$ decimal digits, then multiplied by $s$, which has a + huge imaginary part amplifying the error. + + In this case, $x \mapsto x^{n}$ is treated as a transcendental function and + and in particular acts + componentwise on vector or matrices, even square matrices ! (See + \secref{se:trans}.) If $x$ is $0$ and $n$ is an inexact $0$, this will raise + an exception: + \bprog + ? 4 ^ 1.0 + %1 = 4.0000000000000000000000000000000000000 + ? 0^ 0.0 + *** at top-level: 0^0.0 + *** ^---- + *** _^_: domain error in gpow(0,n): n <= 0 + @eprog + + The library syntax is \fun{GEN}{gpow}{GEN x, GEN n, long prec} + for $x\hbox{\kbd{\pow}}n$. + +Function: _header_polynomials +Class: header +Section: polynomials +Doc: + \section{Polynomials and power series} + + We group here all functions which are specific to polynomials or power + series. Many other functions which can be applied on these objects are + described in the other sections. Also, some of the functions described here + can be applied to other types. + +Function: _header_programming/control +Class: header +Section: programming/control +Doc: + \section{Programming in GP: control statements} + \sidx{programming}\label{se:programming} + + A number of control statements are available in GP. They are simpler and + have a syntax slightly different from their C counterparts, but are quite + powerful enough to write any kind of program. Some of them are specific to + GP, since they are made for number theorists. As usual, $X$ will denote any + simple variable name, and \var{seq} will always denote a sequence of + expressions, including the empty sequence. + + \misctitle{Caveat} In constructs like + \bprog + for (X = a,b, seq) + @eprog\noindent + the variable \kbd{X} is lexically scoped to the loop, leading to possibly + unexpected behavior: + \bprog + n = 5; + for (n = 1, 10, + if (something_nice(), break); + ); + \\ @com at this point \kbd{n} is 5 ! + @eprog\noindent + If the sequence \kbd{seq} modifies the loop index, then the loop + is modified accordingly: + \bprog + ? for (n = 1, 10, n += 2; print(n)) + 3 + 6 + 9 + 12 + @eprog + +Function: _header_programming/parallel +Class: header +Section: programming/parallel +Doc: + \section{Parallel programming} + + These function are only available if PARI was configured using + \kbd{Configure --mt=\dots}. Two multithread interfaces are supported: + + \item POSIX threads + + \item Message passing interface (MPI) + + As a rule, POSIX threads are well-suited for single systems, while MPI is used + by most clusters. However the parallel GP interface does not depend on the + chosen multithread interface: a properly written GP program will work + identically with both. + +Function: _header_programming/specific +Class: header +Section: programming/specific +Doc: + \section{Programming in GP: other specific functions} + \label{se:gp_program} + + In addition to the general PARI functions, it is necessary to have some + functions which will be of use specifically for \kbd{gp}, though a few of these + can be accessed under library mode. Before we start describing these, we recall + the difference between \emph{strings} and \emph{keywords} (see + \secref{se:strings}): the latter don't get expanded at all, and you can type + them without any enclosing quotes. The former are dynamic objects, where + everything outside quotes gets immediately expanded. + +Function: _header_sums +Class: header +Section: sums +Doc: + \section{Sums, products, integrals and similar functions} + \label{se:sums} + + Although the \kbd{gp} calculator is programmable, it is useful to have + a number of preprogrammed loops, including sums, products, and a certain + number of recursions. Also, a number of functions from numerical analysis + like numerical integration and summation of series will be described here. + + One of the parameters in these loops must be the control variable, hence a + simple variable name. In the descriptions, the letter $X$ will always denote + any simple variable name, and represents the formal parameter used in the + function. The expression to be summed, integrated, etc. is any legal PARI + expression, including of course expressions using loops. + + \misctitle{Library mode} + Since it is easier to program directly the loops in library mode, these + functions are mainly useful for GP programming. On the other hand, numerical + routines code a function (to be integrated, summed, etc.) with two parameters + named + \bprog + GEN (*eval)(void*,GEN) + void *E; \\ context: eval(E, x) must evaluate your function at x. + @eprog\noindent + see the Libpari manual for details. + + \misctitle{Numerical integration}\sidx{numerical integration} + The ``double exponential'' (DE) univariate + integration method is implemented in \tet{intnum} and its variants. Romberg + integration is still available under the name \tet{intnumromb}, but + superseded. It is possible to compute numerically integrals to thousands of + decimal places in reasonable time, as long as the integrand is regular. It is + also reasonable to compute numerically integrals in several variables, + although more than two becomes lengthy. The integration domain may be + noncompact, and the integrand may have reasonable singularities at + endpoints. To use \kbd{intnum}, you must split the integral into a sum + of subintegrals where the function has no singularities except at the + endpoints. Polynomials in logarithms are not considered singular, and + neglecting these logs, singularities are assumed to be algebraic (asymptotic + to $C(x-a)^{-\alpha}$ for some $\alpha > -1$ when $x$ is + close to $a$), or to correspond to simple discontinuities of some (higher) + derivative of the function. For instance, the point $0$ is a singularity of + $\text{abs}(x)$. + + Assume the bitprecision is $b$, so we try to achieve an absolute error less + than $2^{-b}$. DE methods use $O(b \log b)$ function evaluations and should + work for both compact and non-compact intervals as long as the integrand is + the restriction of an analytic function to a suitable domain and its behaviour + at infinity is correctly described. + When integrating regular functions on a \emph{compact} interval, away from + poles of the integrand, Gauss-Legendre integration (\tet{intnumgauss}) + is the best choice, using $O(b)$ function evaluations. To integrate + oscillating functions on non-compact interval, the slower but robust + \tet{intnumosc} is available, performing Gaussian integration on intervals of + length the half-period (or quasi-period) and using Sidi's $mW$ algorithm to + extrapolate their sum. If poles are close to the integration interval, + Gaussian integration may run into difficulties and it is then advisable to + split the integral using \kbd{intnum} to get away from poles, then + \kbd{intnumosc} for the remainder. + + For maximal efficiency, abscissas and integration + weights can be precomputed, respectively using \tet{intnuminit} ($O(b^{2})$) + or \tet{intnumgaussinit} ($O(b^{3})$). + + \misctitle{Numerical summation}\sidx{numerical summation} + + Many numerical summation methods are available to approximate + $\sum_{n\geq n_{0}} f(n)$ at accuracy $2^{-b}$: the overall best choice should + be \tet{sumnum}, which uses Euler-MacLaurin (and $O(b\log b)$ function + evaluations); initialization time (\tet{sumnuminit}) is $O(b^{3})$. + Also available are + + \item Abel-Plana summation (\tet{sumnumap}), + also $O(b\log b)$ function evaluations and $O(b^{3})$ initialization + (\tet{sumnumapinit}) with a larger implied constant; + + \item Lagrange summation (\tet{sumnumlagrange}) uses $O(b)$ evaluations + but more brittle and the asymptotic behaviour of $f$ must be correctly + indicated. Initialization (\tet{sumnumlagrangeinit}) can vary from $O(b^{2})$ + to $O(b^{3})$ depending on the asymptotic behaviour. + + \item Sidi summation (\tet{sumnumsidi}) uses $O(b)$ evaluations and should + be more robust than Lagrange summation. No initialization is needed. + + \item Monien summation (\tet{sumnummonien}) uses $O(b/\log b)$ evaluations + but is even more brittle than Lagrange and also has a $O(b^{3})$ initialization + (\kbd{summonieninit}). + + \item To sum rational functions, use \tet{sumnumrat}. + + All the function so far require $f$ to be be the restriction to integers + of a regular function on the reals, and even on the complex numbers for + Monien summation. The following algorithms allow functions defined + only on the integers, under asumptions that are hard to verify. They are + best used heuristically since they in fact are often valid when those + asumptions do not hold, and for instance often yield a result for divergent + series (e.g., Borel resummation). + + \item To sum alternating series, use \tet{sumalt}, which requires + $O(b)$ function evaluations. + + \item To sum functions of a fixed sign, \tet{sumpos} + uses van Wijngarten's trick to reduce to an alternating series, + for a cost of $O(b\log b)$ function evaluations but beware that $f$ must be + evaluated at large integers, of the order of $2^{b/\alpha}$ if we assume + that $f(n) = O(1 / n^{\alpha+1})$ for some $\alpha > 0$. + +Function: _header_transcendental +Class: header +Section: transcendental +Doc: + \section{Transcendental functions}\label{se:trans} + + Since the values of transcendental functions cannot be exactly represented, + these functions will always return an inexact object: a real number, + a complex number, a $p$-adic number or a power series. All these objects + have a certain finite precision. + + As a general rule, which of course in some cases may have exceptions, + transcendental functions operate in the following way: + + \item If the argument is either a real number or an inexact complex number + (like \kbd{1.0 + I} or \kbd{Pi*I} but not \kbd{2 - 3*I}), then the + computation is done with the precision of the argument. + In the example below, we see that changing the precision to $50$ digits does + not matter, because $x$ only had a precision of $19$ digits. + \bprog + ? \p 15 + realprecision = 19 significant digits (15 digits displayed) + ? x = Pi/4 + %1 = 0.785398163397448 + ? \p 50 + realprecision = 57 significant digits (50 digits displayed) + ? sin(x) + %2 = 0.7071067811865475244 + @eprog + + Note that even if the argument is real, the result may be complex + (e.g.~$\text{acos}(2.0)$ or $\text{acosh}(0.0)$). See each individual + function help for the definition of the branch cuts and choice of principal + value. + + \item If the argument is either an integer, a rational, an exact complex + number or a quadratic number, it is first converted to a real + or complex number using the current \idx{precision}, which can be + view and manipulated using the defaults \tet{realprecision} (in decimal + digits) or \tet{realbitprecision} (in bits). This precision can be changed + indifferently + + \item in decimal digits: use \b{p} or \kbd{default(realprecision,...)}. + + \item in bits: use \b{pb} or \kbd{default(realbitprecision,...)}. + + After this conversion, the computation proceeds as above for real or complex + arguments. + + In library mode, the \kbd{realprecision} does not matter; instead the + precision is taken from the \kbd{prec} parameter which every transcendental + function has. As in \kbd{gp}, this \kbd{prec} is not used when the argument + to a function is already inexact. Note that the argument \var{prec} stands + for the length in words of a real number, including codewords. Hence we must + have $\var{prec} \geq 3$. (Some functions allow a \kbd{bitprec} argument + instead which allow finer granularity.) + + Some accuracies attainable on 32-bit machines cannot be attained + on 64-bit machines for parity reasons. For example, an accuracy + of 28 decimal digits on 32-bit machines corresponds to \var{prec} having + the value 5, for a mantissa of $3 \times 32 = 96$ bits. But this cannot be + attained on 64-bit machines: we can attain either 64 or 128 bits, but values + in between. + + \item If the argument is a polmod (representing an algebraic number), + then the function is evaluated for every possible complex embedding of that + algebraic number. A column vector of results is returned, with one component + for each complex embedding. Therefore, the number of components equals + the degree of the \typ{POLMOD} modulus. + + \item If the argument is an intmod or a $p$-adic, at present only a + few functions like \kbd{sqrt} (square root), \kbd{sqr} (square), \kbd{log}, + \kbd{exp}, powering, \kbd{teichmuller} (Teichm\"uller character) and + \kbd{agm} (arithmetic-geometric mean) are implemented. + + Note that in the case of a $2$-adic number, $\kbd{sqr}(x)$ may not be + identical to $x*x$: for example if $x = 1+O(2^{5})$ and $y = 1+O(2^{5})$ then + $x*y = 1+O(2^{5})$ while $\kbd{sqr}(x) = 1+O(2^{6})$. Here, $x * x$ yields the + same result as $\kbd{sqr}(x)$ since the two operands are known to be + \emph{identical}. The same statement holds true for $p$-adics raised to the + power $n$, where $v_{p}(n) > 0$. + + \misctitle{Remark} If we wanted to be strictly consistent with + the PARI philosophy, we should have $x*y = (4 \mod 8)$ and $\kbd{sqr}(x) = + (4 \mod 32)$ when both $x$ and $y$ are congruent to $2$ modulo $4$. + However, since intmod is an exact object, PARI assumes that the modulus + must not change, and the result is hence $(0\, \mod\, 4)$ in both cases. On + the other hand, $p$-adics are not exact objects, hence are treated + differently. + + \item If the argument is a polynomial, a power series or a rational function, + it is, if necessary, first converted to a power series using the current + series precision, held in the default \tet{seriesprecision}. This precision + (the number of significant terms) can be changed using \b{ps} or + \kbd{default(seriesprecision,...)}. Then the Taylor series expansion of the + function around $X=0$ (where $X$ is the main variable) is computed to a + number of terms depending on the number of terms of the argument and the + function being computed. + + Under \kbd{gp} this again is transparent to the user. When programming in + library mode, however, it is \emph{strongly} advised to perform an explicit + conversion to a power series first, as in + \bprog + x = gtoser(x, gvar(x), seriesprec) + @eprog\noindent + where the number of significant terms \kbd{seriesprec} can be specified + explicitly. If you do not do this, a global variable \kbd{precdl} is used + instead, to convert polynomials and rational functions to a power series with + a reasonable number of terms; tampering with the value of this global + variable is \emph{deprecated} and strongly discouraged. + + \item If the argument is a vector or a matrix, the result is the + \emph{componentwise} evaluation of the function. In particular, transcendental + functions on square matrices, are not built-in. For this you can use the + following technique, which is neither very efficient nor numerical stable, + but is often good enough provided we restrict to diagonalizable matrices: + \bprog + mateval(f, M) = + { my([L, H] = mateigen(M, 1)); + H * matdiagonal(f(L)) * H^(-1); + } + ? A = [13,2;10,14]; + ? a = mateval(sqrt, A) /*@Ccom approximates $\sqrt{A}$ */ + %2 = + [3.5522847498307933... 0.27614237491539669...] + + [1.3807118745769834... 3.69035593728849174...] + + ? exponent(a^2 - A) + %3 = -123 \\ OK + + ? b = mateval(exp, A); + ? exponent(mateval(log, b) - A) + %5 = -115 \\ tolerable + + @eprog The absolute error depends on the condition number of the base + change matrix $H$ and on the largest $|f(\lambda)|$, where $\lambda$ runs + through the eigenvalues. If $M$ is real symmetric, you may use + \kbd{qfjacobi} instead of \kbd{mateigen}. + + Of course when the input is not diagonalizable, this function produces junk: + \bprog + ? mateval(sqrt, [0,1;0,0]) + %6 = \\ oops ... + [0.E-57 0] + + [ 0 0] + @eprog + +Function: _iferr_CATCH +Class: gp2c_internal +Description: + (0) pari_CATCH(CATCH_ALL) + (small) pari_CATCH2(__iferr_old$1, CATCH_ALL) + +Function: _iferr_CATCH_reset +Class: gp2c_internal +Description: + (0):void pari_CATCH_reset() + (small):void pari_CATCH2_reset(__iferr_old$1) + +Function: _iferr_ENDCATCH +Class: gp2c_internal +Description: + (0) pari_ENDCATCH + (small) pari_ENDCATCH2(__iferr_old$1) + +Function: _iferr_error +Class: gp2c_internal +Description: + ():error pari_err_last() + +Function: _iferr_rethrow +Class: gp2c_internal +Description: + (error):void pari_err(0, $1) + +Function: _inv +Class: basic +Section: programming/internals +C-Name: ginv +Prototype: G +Help: return x^-1 where n is a small integer + +Function: _lerch_worker +Class: basic +Section: programming/internals +C-Name: lerch_worker +Prototype: GG +Help: _lerch_worker(E,t): worker for lerchzeta +Doc: auxiliary. + +Function: _lfuninit_theta2_worker +Class: basic +Section: programming/internals +C-Name: lfuninit_theta2_worker +Prototype: LGGGGGG +Help: worker for lfuninit using theta2 + +Function: _lfuninit_worker +Class: basic +Section: programming/internals +C-Name: lfuninit_worker +Prototype: LGGGGGGGG +Help: worker for lfuninit + +Function: _low_stack_lim +Class: gp2c_internal +Description: + (pari_sp,pari_sp):bool low_stack($1, stack_lim($2, 1)) + +Function: _maxprime +Class: gp2c_internal +Description: + ():small maxprime() + +Function: _multi_if +Class: basic +Section: programming/internals +C-Name: ifpari_multi +Prototype: GE* +Help: internal variant of if() that allows more than 3 arguments. + +Function: _ndec2nbits +Class: gp2c_internal +Description: + (small):small ndec2nbits($1) + +Function: _ndec2prec +Class: gp2c_internal +Description: + (small):small ndec2prec($1) + +Function: _nflist_A462_worker +Class: basic +Section: programming/internals +C-Name: nflist_A462_worker +Prototype: GGGGG +Help: nflist_A462_worker(P3,X,Xinf,listarch,GAL): auxiliary. +Doc: auxiliary + +Function: _nflist_A46S46P_worker +Class: basic +Section: programming/internals +C-Name: nflist_A46S46P_worker +Prototype: GGGG +Help: nflist_A46S46P_worker(P3,Xinf,sqX,cards): auxiliary. +Doc: auxiliary + +Function: _nflist_A4S4_worker +Class: basic +Section: programming/internals +C-Name: nflist_A4S4_worker +Prototype: GGGG +Help: nflist_A4S4_worker(P3,X,Xinf,cardsprec): auxiliary. +Doc: auxiliary + +Function: _nflist_C32C4_worker +Class: basic +Section: programming/internals +C-Name: nflist_C32C4_worker +Prototype: GGGG +Help: nflist_C32C4_worker(P4,X,Xinf,GAL): auxiliary. +Doc: auxiliary + +Function: _nflist_C32D4_worker +Class: basic +Section: programming/internals +C-Name: nflist_C32D4_worker +Prototype: GGGG +Help: nflist_C32D4_worker(P,X,Xinf,gs): auxiliary. +Doc: auxiliary + +Function: _nflist_C3C3_worker +Class: basic +Section: programming/internals +C-Name: nflist_C3C3_worker +Prototype: GGGG +Help: nflist_C3C3_worker(gi,V3,V3D,X): auxiliary. +Doc: auxiliary + +Function: _nflist_C3_worker +Class: basic +Section: programming/internals +C-Name: nflist_C3_worker +Prototype: GG +Help: nflist_C3_worker(gv,T): auxiliary. +Doc: auxiliary + +Function: _nflist_C4vec_worker +Class: basic +Section: programming/internals +C-Name: nflist_C4vec_worker +Prototype: GGGG +Help: nflist_C4vec_worker(gm,X,Xinf,X2,gs): auxiliary. +Doc: auxiliary + +Function: _nflist_C5_worker +Class: basic +Section: programming/internals +C-Name: nflist_C5_worker +Prototype: GG +Help: nflist_C5_worker(N,bnfC5): auxiliary. +Doc: auxiliary + +Function: _nflist_C6_worker +Class: basic +Section: programming/internals +C-Name: nflist_C6_worker +Prototype: GGGGG +Help: nflist_C6_worker(P3,X,Xinf,M,T): auxiliary. +Doc: auxiliary + +Function: _nflist_C9_worker +Class: basic +Section: programming/internals +C-Name: nflist_C9_worker +Prototype: GGG +Help: nflist_C9_worker(P,X,Xinf): auxiliary. +Doc: auxiliary + +Function: _nflist_CL_worker +Class: basic +Section: programming/internals +C-Name: nflist_CL_worker +Prototype: GGG +Help: nflist_CL_worker(Fcond,bnf,ellprec): auxiliary. +Doc: auxiliary + +Function: _nflist_D4_worker +Class: basic +Section: programming/internals +C-Name: nflist_D4_worker +Prototype: GGGG +Help: nflist_D4_worker(D,X,Xinf,listarch): auxiliary. +Doc: auxiliary + +Function: _nflist_D612_worker +Class: basic +Section: programming/internals +C-Name: nflist_D612_worker +Prototype: GGGG +Help: nflist_D612_worker(P3,X,Xinf,X2,limd2s2): auxiliary. +Doc: auxiliary + +Function: _nflist_D9_worker +Class: basic +Section: programming/internals +C-Name: nflist_D9_worker +Prototype: GGG +Help: nflist_D9_worker(P2,X,Xinf): auxiliary. +Doc: auxiliary + +Function: _nflist_DL_worker +Class: basic +Section: programming/internals +C-Name: nflist_DL_worker +Prototype: GGGGGG +Help: nflist_DL_worker(P2,X1p,X0p,X,Xinf,ells): auxiliary. +Doc: auxiliary + +Function: _nflist_Mgen_worker +Class: basic +Section: programming/internals +C-Name: nflist_Mgen_worker +Prototype: GGGG +Help: nflist_Mgen_worker(field,X,Xinf,ella): auxiliary. +Doc: auxiliary + +Function: _nflist_S32_worker +Class: basic +Section: programming/internals +C-Name: nflist_S32_worker +Prototype: GGGGG +Help: nflist_S32_worker(all1,X,Xinf,V3,sprec): auxiliary. +Doc: auxiliary + +Function: _nflist_S36_worker +Class: basic +Section: programming/internals +C-Name: nflist_S36_worker +Prototype: GGG +Help: nflist_S36_worker(pol,X,Xinf,X2): auxiliary. +Doc: auxiliary + +Function: _nflist_S3C3_worker +Class: basic +Section: programming/internals +C-Name: nflist_S3C3_worker +Prototype: GGG +Help: nflist_S3C3_worker(D2,X,Xinf,X2): auxiliary. +Doc: auxiliary + +Function: _nflist_S3I_worker +Class: basic +Section: programming/internals +C-Name: nflist_S3I_worker +Prototype: GG +Help: nflist_S3I_worker(ga,ALLCTS): auxiliary. +Doc: auxiliary + +Function: _nflist_S3R_worker +Class: basic +Section: programming/internals +C-Name: nflist_S3R_worker +Prototype: GG +Help: nflist_S3R_worker(ga,ALLCTS): auxiliary. +Doc: auxiliary + +Function: _nflist_S462_worker +Class: basic +Section: programming/internals +C-Name: nflist_S462_worker +Prototype: GGGGG +Help: nflist_S462_worker(P3,X,Xinf,listarch,GAL): auxiliary. +Doc: auxiliary + +Function: _nflist_S46M_worker +Class: basic +Section: programming/internals +C-Name: nflist_S46M_worker +Prototype: GGGG +Help: nflist_S46M_worker(P3,X,Xinf,sprec): auxiliary. +Doc: auxiliary + +Function: _nflist_V4_worker +Class: basic +Section: programming/internals +C-Name: nflist_V4_worker +Prototype: GGGG +Help: nflist_V4_worker(D1,X,Xinf,gs): auxiliary. +Doc: auxiliary + +Function: _norange +Class: gp2c_internal +Description: + ():small LONG_MAX + +Function: _nxMV_polint_worker +Class: basic +Section: programming/internals +C-Name: nxMV_polint_center_tree_worker +Prototype: GGGGG +Help: used for parallel chinese +Doc: used for parallel chinese + +Function: _parapply_slice_worker +Class: basic +Section: programming/internals +C-Name: parapply_slice_worker +Prototype: GG +Help: _parapply_slice_worker(v,C): return [C(x) | x<-v]. + +Function: _pareval_worker +Class: basic +Section: programming/internals +C-Name: pareval_worker +Prototype: G +Help: _pareval_worker(C): evaluate the closure C. + +Function: _parfor_init +Class: gp2c_internal +Help: Initializes parameters for parfor. +Description: + (parfor, gen, gen, gen):void parfor_init(&$1, $2, $3, $4) + +Function: _parfor_next +Class: gp2c_internal +Help: Next value for parfor. +Description: + (parfor):gen parfor_next(&$1) + +Function: _parfor_stop +Class: gp2c_internal +Help: Stop function for parfor. +Description: + (parfor):void parfor_stop(&$1) + +Function: _parfor_worker +Class: basic +Section: programming/internals +C-Name: parfor_worker +Prototype: GG +Help: _parfor_worker(i,C): evaluate the closure C on i and return [i,C(i)] + +Function: _parforeach_init +Class: gp2c_internal +Help: Initializes parameters for parforeach. +Description: + (parforeach,gen,gen):void parforeach_init(&$1, $2, $3) + +Function: _parforeach_next +Class: gp2c_internal +Help: Next value for parforeach. +Description: + (parforeach):gen parforeach_next(&$1) + +Function: _parforeach_stop +Class: gp2c_internal +Help: Stop function for parforeach. +Description: + (parforeach):void parforeach_stop(&$1) + +Function: _parforprime_init +Class: gp2c_internal +Help: Initializes parameters for parforprime. +Description: + (parforprime, gen, ?gen, gen):void parforprime_init(&$1, $2, $3, $4) + +Function: _parforprime_next +Class: gp2c_internal +Help: Next value for parforprime +Description: + (parforprime):gen parforprime_next(&$1) + +Function: _parforprime_stop +Class: gp2c_internal +Help: Stop function for parforprime. +Description: + (parforprime):void parforprime_stop(&$1) + +Function: _parforprimestep_init +Class: gp2c_internal +Help: Initializes parameters for parforprime. +Description: + (parforprime, gen, ?gen, gen, gen):void parforprimestep_init(&$1, $2, $3, $4, $5) + +Function: _parforstep_init +Class: gp2c_internal +Help: Initializes parameters for parforstep. +Description: + (parforstep, gen, ?gen, gen, gen):void parforstep_init(&$1, $2, $3, $4, $5) + +Function: _parforstep_next +Class: gp2c_internal +Help: Next value for parforstep +Description: + (parforstep):gen parforstep_next(&$1) + +Function: _parforstep_stop +Class: gp2c_internal +Help: Stop function for parforstep. +Description: + (parforstep):void parforstep_stop(&$1) + +Function: _parforvec_init +Class: gp2c_internal +Help: Initializes parameters for parforvec. +Description: + (parforvec,vec,closure,?small):void parforvec_init(&$1, $2, $3, $4) + +Function: _parforvec_next +Class: gp2c_internal +Help: Next value for parforvec. +Description: + (parforvec):gen parforvec_next(&$1) + +Function: _parforvec_stop +Class: gp2c_internal +Help: Stop function for parforvec. +Description: + (parforvec):void parforvec_stop(&$1) + +Function: _parsqf_worker +Class: basic +Section: programming/internals +C-Name: parsqf_worker +Prototype: GGG +Help: _parsqf_worker(gk,vR,data): auxiliary. +Doc: auxiliary + +Function: _parsum_slice_worker +Class: basic +Section: programming/internals +C-Name: parsum_slice_worker +Prototype: GGGG +Help: _parsum_slice_worker(a,b,m,C): return sum(k=0,(b-a)\m,C(a+k*m)). + a and m must be integers and m must be positive. + +Function: _parsumprimefun_worker +Class: basic +Section: programming/internals +C-Name: parsumprimefun_worker +Prototype: GGGGGG +Help: _parsumprimefun_worker(gk,s,zerf,data,vW,f): auxiliary +Doc: auxiliary + +Function: _partmap_reverse_frac_worker +Class: basic +Section: programming/internals +C-Name: partmap_reverse_frac_worker +Prototype: GGGGGL +Help: worker for partmap_reverse_frac + +Function: _parvector_worker +Class: basic +Section: programming/internals +C-Name: parvector_worker +Prototype: GG +Help: _parvector_worker(i,C): evaluate the closure C on i. + +Function: _polclass_worker +Class: basic +Section: programming/internals +C-Name: polclass_worker +Prototype: GGG +Help: used by polclass +Doc: used by polclass + +Function: _polint_worker +Class: basic +Section: programming/internals +C-Name: nmV_polint_center_tree_worker +Prototype: GGGGG +Help: used for parallel chinese +Doc: used for parallel chinese + +Function: _polmodular_worker +Class: basic +Section: programming/internals +C-Name: polmodular_worker +Prototype: GUGGGGLGGGG +Help: used by polmodular +Doc: used by polmodular + +Function: _primecertisvalid_ecpp_worker +Class: basic +Section: programming/internals +C-Name: primecertisvalid_ecpp_worker +Prototype: G +Help: worker for primecertisvalid + +Function: _proto_code +Class: gp2c_internal +Help: Code for argument of a function +Description: + (var) n + (C!long) L + (C!ulong) U + (C!GEN) G + (C!char*) s + +Function: _proto_max_args +Class: gp2c_internal +Help: Max number of arguments supported by install. +Description: + (20) + +Function: _proto_ret +Class: gp2c_internal +Help: Code for return value of functions +Description: + (C!void) v + (C!int) i + (C!long) l + (C!ulong) u + (C!GEN) + +Function: _ramanujantau_worker +Class: basic +Section: programming/internals +C-Name: ramanujantau_worker +Prototype: GGGG +Help: worker for ramanujantau + +Function: _safecoeff +Class: basic +Section: symbolic_operators +Help: safe version of x[a], x[,a] and x[a,b]. Must be lvalues. +Description: + (vecsmall,small):small *safeel($1, $2) + (list,small):gen:copy *safelistel($1, $2) + (gen,small):gen:copy *safegel($1, $2) + (gen,small,small):gen:copy *safegcoeff($1, $2, $3) + +Function: _serh_worker +Class: basic +Section: programming/internals +C-Name: serh_worker +Prototype: GGGGG +Help: _serh_worker(gk,V,a,ns,gprec): auxiliary. +Doc: auxiliary + +Function: _stack_lim +Class: gp2c_internal +Description: + (pari_sp,small):pari_sp stack_lim($1, $2) + +Function: _strtoclosure +Class: gp2c_internal +Description: + (str):closure strtofunction($1) + (str,gen,...):closure strtoclosure($1, ${nbarg 1 sub}, $3) + +Function: _taugen_n_worker +Class: basic +Section: programming/internals +C-Name: taugen_n_worker +Prototype: GGG +Help: worker for ramanujantau + +Function: _tovec +Class: gp2c_internal +Help: Create a vector holding the arguments (shallow) +Description: + ():vec cgetg(1, t_VEC) + (gen):vec mkvec($1) + (gen,gen):vec mkvec2($1, $2) + (gen,gen,gen):vec mkvec3($1, $2, $3) + (gen,gen,gen,gen):vec mkvec4($1, $2, $3, $4) + (gen,gen,gen,gen,gen):vec mkvec5($1, $2, $3, $4, $5) + (gen,...):vec mkvecn($#, $2) + +Function: _tovecprec +Class: gp2c_internal +Help: Create a vector holding the arguments and prec (shallow) +Description: + ():vec:prec mkvecs($prec) + (gen):vec:prec mkvec2($1, stoi($prec)) + (gen,gen):vec:prec mkvec3($1, $2, stoi($prec)) + (gen,gen,gen):vec:prec mkvec4($1, $2, $3, stoi($prec)) + (gen,gen,gen,gen):vec:prec mkvec5($1, $2, $3, $4, stoi($prec)) + (gen,...):vec:prec mkvecn(${nbarg 1 add}, $2, stoi($prec)) + +Function: _type_preorder +Class: gp2c_internal +Help: List of chains of type preorder. +Description: + (empty, void, bool, small, int, mp, gen) + (empty, real, mp) + (empty, bptr, small) + (empty, bool, lg, small) + (empty, bool, small_int, small) + (empty, bool, usmall, small) + (empty, void, negbool, bool) + (empty, typ, str, genstr,gen) + (empty, errtyp, str) + (empty, vecsmall, gen) + (empty, vecvecsmall, vec, gen) + (empty, list, gen) + (empty, closure, gen) + (empty, error, gen) + (empty, bnr, bnf, nf, vec) + (empty, bnr, bnf, clgp, vec) + (empty, ell, vec) + (empty, prid, vec) + (empty, gal, vec) + (empty, var, pol, gen) + (empty, Fp, Fq, gen) + (empty, FpX, FqX, gen) + +Function: _typedef +Class: gp2c_internal +Description: + (empty) void + (void) void + (negbool) long + (bool) long + (small_int) int + (usmall) ulong + (small) long + (int) GEN + (real) GEN + (mp) GEN + (lg) long + (vecsmall) GEN + (vec) GEN + (vecvecsmall) GEN + (list) GEN + (var) long + (pol) GEN + (gen) GEN + (closure) GEN + (error) GEN + (genstr) GEN + (str) char* + (bptr) byteptr + (forcomposite) forcomposite_t + (forpart) forpart_t + (forperm) forperm_t + (forprime) forprime_t + (forsubset) forsubset_t + (forvec) forvec_t + (parfor) parfor_t + (parforstep) parforstep_t + (parforeach) parforeach_t + (parforprime) parforprime_t + (parforvec) parforvec_t + (func_GG) func_GG + (pari_sp) pari_sp + (typ) long + (errtyp) long + (nf) GEN + (bnf) GEN + (bnr) GEN + (ell) GEN + (clgp) GEN + (prid) GEN + (gal) GEN + (Fp) GEN + (FpX) GEN + (Fq) GEN + (FqX) GEN + +Function: _u_forprime_init +Class: gp2c_internal +Help: Initialize forprime_t (ulong version). +Description: + (forprime,small,):void u_forprime_init(&$1, $2, LONG_MAX); + (forprime,small,small):void u_forprime_init(&$1, $2, $3); + +Function: _u_forprime_next +Class: gp2c_internal +Help: Compute the next prime (ulong version). +Description: + (forprime):small u_forprime_next(&$1) + +Function: _void_if +Class: basic +Section: programming/internals +C-Name: ifpari_void +Prototype: vGDIDI +Help: internal variant of if() that does not return a value. + +Function: _wrap_G +Class: gp2c_internal +C-Name: gp_call +Prototype: G +Description: + (gen):gen $1 + +Function: _wrap_GG +Class: gp2c_internal +C-Name: gp_call2 +Prototype: GG +Description: + (gen):gen $1 + +Function: _wrap_Gp +Class: gp2c_internal +C-Name: gp_callprec +Prototype: Gp +Description: + (gen):gen $1 + +Function: _wrap_bG +Class: gp2c_internal +C-Name: gp_callbool +Prototype: lG +Description: + (bool):bool $1 + +Function: _wrap_vG +Class: gp2c_internal +C-Name: gp_callvoid +Prototype: lG +Description: + (void):small 0 + +Function: _||_ +Class: basic +Section: symbolic_operators +C-Name: orpari +Prototype: GE +Help: a||b: boolean operator "or" (inclusive). +Description: + (bool, bool):bool:parens $(1) || $(2) + +Function: _~ +Class: basic +Section: symbolic_operators +C-Name: gtrans +Prototype: G +Help: x~: transpose of x. +Description: + (vec):vec gtrans($1) + (gen):gen gtrans($1) + +Function: abs +Class: basic +Section: transcendental +C-Name: gabs +Prototype: Gp +Help: abs(x): absolute value (or modulus) of x. +Description: + (small):small labs($1) + (int):int mpabs($1) + (real):real mpabs($1) + (mp):mp mpabs($1) + (gen):gen:prec gabs($1, $prec) +Doc: absolute value of $x$ (modulus if $x$ is complex). + Rational functions are not allowed. Contrary to most transcendental + functions, an exact argument is \emph{not} converted to a real number before + applying \kbd{abs} and an exact result is returned if possible. + \bprog + ? abs(-1) + %1 = 1 + ? abs(3/7 + 4/7*I) + %2 = 5/7 + ? abs(1 + I) + %3 = 1.414213562373095048801688724 + @eprog\noindent + If $x$ is a polynomial, returns $-x$ if the leading coefficient is + real and negative else returns $x$. For a power series, the constant + coefficient is considered instead. + +Function: acos +Class: basic +Section: transcendental +C-Name: gacos +Prototype: Gp +Help: acos(x): arc cosine of x. +Doc: principal branch of $\cos^{-1}(x) = -i \log (x + i\sqrt{1-x^{2}})$. + In particular, $\Re(\text{acos}(x))\in [0,\pi]$ and if $x\in \R$ and $|x|>1$, + then $\text{acos}(x)$ is complex. The branch cut is in two pieces: + $]-\infty,-1]$ , continuous with quadrant II, and $[1,+\infty[$, continuous + with quadrant IV. We have $\text{acos}(x) = \pi/2 - \text{asin}(x)$ for all + $x$. + +Function: acosh +Class: basic +Section: transcendental +C-Name: gacosh +Prototype: Gp +Help: acosh(x): inverse hyperbolic cosine of x. +Doc: principal branch of $\cosh^{-1}(x) = 2 + \log(\sqrt{(x+1)/2} + \sqrt{(x-1)/2})$. In particular, + $\Re(\text{acosh}(x))\geq 0$ and + $\Im(\text{acosh}(x))\in ]-\pi,\pi]$; if $x\in \R$ and $x<1$, then + $\text{acosh}(x)$ is complex. + +Function: addhelp +Class: basic +Section: programming/specific +C-Name: addhelp +Prototype: vrs +Help: addhelp(sym,str): add/change help message for the symbol sym. +Doc: changes the help message for the symbol \kbd{sym}. The string \var{str} + is expanded on the spot and stored as the online help for \kbd{sym}. It is + recommended to document global variables and user functions in this way, + although \kbd{gp} will not protest if you don't. + + You can attach a help text to an alias, but it will never be + shown: aliases are expanded by the \kbd{?} help operator and we get the help + of the symbol the alias points to. Nothing prevents you from modifying the + help of built-in PARI functions. But if you do, we would like to hear why you + needed it! + + Without \tet{addhelp}, the standard help for user functions consists of its + name and definition. + \bprog + gp> f(x) = x^2; + gp> ?f + f = + (x)->x^2 + + @eprog\noindent Once addhelp is applied to $f$, the function code is no + longer included. It can still be consulted by typing the function name: + \bprog + gp> addhelp(f, "Square") + gp> ?f + Square + + gp> f + %2 = (x)->x^2 + @eprog + +Function: addprimes +Class: basic +Section: number_theoretical +C-Name: addprimes +Prototype: DG +Help: addprimes({x=[]}): add primes in the vector x to the prime table to + be used in trial division. x may also be a single integer. Composite + "primes" are NOT allowed. +Doc: adds the integers contained in the + vector $x$ (or the single integer $x$) to a special table of + ``user-defined primes'', and returns that table. Whenever \kbd{factor} is + subsequently called, it will trial divide by the elements in this table. + If $x$ is empty or omitted, just returns the current list of extra + primes. + \bprog + ? addprimes(37975227936943673922808872755445627854565536638199) + ? factor(15226050279225333605356183781326374297180681149613806\ + 88657908494580122963258952897654000350692006139) + %2 = + [37975227936943673922808872755445627854565536638199 1] + + [40094690950920881030683735292761468389214899724061 1] + ? ## + *** last result computed in 0 ms. + @eprog + + The entries in $x$ must be primes: there is no internal check, even if + the \tet{factor_proven} default is set. To remove primes from the list use + \kbd{removeprimes}. + +Function: agm +Class: basic +Section: transcendental +C-Name: agm +Prototype: GGp +Help: agm(x,y): arithmetic-geometric mean of x and y. +Doc: arithmetic-geometric mean of $x$ and $y$. In the + case of complex or negative numbers, the optimal AGM is returned + (the largest in absolute value over all choices of the signs of the square + roots). $p$-adic or power series arguments are also allowed. Note that + a $p$-adic agm exists only if $x/y$ is congruent to 1 modulo $p$ (modulo + 16 for $p=2$). $x$ and $y$ cannot both be vectors or matrices. + +Function: airy +Class: basic +Section: transcendental +C-Name: airy +Prototype: Gp +Help: airy(z): Airy [Ai,Bi] function of argument z. +Doc: airy $[Ai,Bi]$ functions of argument $z$. + \bprog + ? [A,B] = airy(1); + ? A + %2 = 0.13529241631288141552414742351546630617 + ? B + %3 = 1.2074235949528712594363788170282869954 + @eprog\noindent + +Function: alarm +Class: basic +Section: programming/specific +C-Name: gp_alarm +Prototype: D0,L,DE +Help: alarm({s = 0},{code}): if code is omitted, trigger an "e_ALARM" + exception after s seconds (wall-clock time), cancelling any previously set + alarm; stop a pending alarm if s = 0 or is omitted. Otherwise, evaluate code, + aborting after s seconds. +Doc: if \var{code} is omitted, trigger an \var{e\_ALARM} exception after $s$ + seconds (wall-clock time), cancelling any previously set alarm; stop a pending + alarm if $s = 0$ or is omitted. + + Otherwise, if $s$ is positive, the function evaluates \var{code}, + aborting after $s$ seconds. The return value is the value of \var{code} if + it ran to completion before the alarm timeout, and a \typ{ERROR} object + otherwise. + \bprog + ? p = nextprime(10^25); q = nextprime(10^26); N = p*q; + ? E = alarm(1, factor(N)); + ? type(E) + %3 = "t_ERROR" + ? print(E) + %4 = error("alarm interrupt after 964 ms.") + ? alarm(10, factor(N)); \\ enough time + %5 = + [ 10000000000000000000000013 1] + + [100000000000000000000000067 1] + @eprog\noindent Here is a more involved example: the function + \kbd{timefact(N,sec)} below tries to factor $N$ and gives up after \var{sec} + seconds, returning a partial factorization. + \bprog + \\ Time-bounded partial factorization + default(factor_add_primes,1); + timefact(N,sec)= + { + F = alarm(sec, factor(N)); + if (type(F) == "t_ERROR", factor(N, 2^24), F); + } + @eprog\noindent We either return the factorization directly, or replace the + \typ{ERROR} result by a simple bounded factorization \kbd{factor(N, 2\pow 24)}. + Note the \tet{factor_add_primes} trick: any prime larger than $2^{24}$ + discovered while attempting the initial factorization is stored and + remembered. When the alarm rings, the subsequent bounded factorization finds + it right away. + + \misctitle{Caveat} It is not possible to set a new alarm \emph{within} + another \kbd{alarm} code: the new timer erases the parent one. + + \misctitle{Caveat2} In a parallel-enabled \kbd{gp}, if the \var{code} + involves parallel subtasks, then \kbd{alarm} may not return right away: il + will prevent new tasks from being launched but will not interrupt previously + launched secondary threads. This avoids leaving the system in an + inconsistent state. + +Function: algadd +Class: basic +Section: algebras +C-Name: algadd +Prototype: DGGG +Help: algadd({al},x,y): element x+y in al (Hamilton quaternions if omitted). +Doc: Given two elements $x$ and $y$ in \var{al} (Hamilton quaternions if + omitted), computes their sum $x+y$ in the algebra~\var{al}. + \bprog + ? A = alginit(nfinit(y),[-1,1]); + ? algadd(A,[1,x]~,[1,2,3,4]~) + % = [2, 1, 1, 6]~ + ? algadd(,sqrt(2+I),[-1,0,1,2]~) + % = [0.4553466902, 0.3435607497, 1, 2]~ + @eprog + + Also accepts matrices with coefficients in \var{al}. + + If~$x$ and~$y$ are given in the same format, then one should simply use \kbd{+} + instead of \kbd{algadd}. + +Function: algalgtobasis +Class: basic +Section: algebras +C-Name: algalgtobasis +Prototype: GG +Help: algalgtobasis(al,x): transforms the element x of the algebra al into a + column vector on the integral basis of al. +Doc: Given an element \var{x} in the central simple algebra \var{al} output + by \tet{alginit}, transforms it to a column vector on the integral basis of + \var{al}. This is the inverse function of \tet{algbasistoalg}. + \bprog + ? A = alginit(nfinit(y^2-5),[2,y]); + ? algalgtobasis(A,[y,1]~) + %2 = [0, 2, 0, -1, 2, 0, 0, 0]~ + ? algbasistoalg(A,algalgtobasis(A,[y,1]~)) + %3 = [Mod(Mod(y, y^2 - 5), x^2 - 2), 1]~ + @eprog + +Function: algaut +Class: basic +Section: algebras +C-Name: algaut +Prototype: mG +Help: algaut(al): the stored automorphism of the splitting field of the + cyclic algebra al. +Doc: Given a cyclic algebra $\var{al} = (L/K,\sigma,b)$ output by + \tet{alginit}, returns the automorphism $\sigma$. + \bprog + ? nf = nfinit(y); + ? p = idealprimedec(nf,7)[1]; + ? p2 = idealprimedec(nf,11)[1]; + ? A = alginit(nf,[3,[[p,p2],[1/3,2/3]],[0]]); + ? algaut(A) + %5 = -1/3*x^2 + 1/3*x + 26/3 + @eprog + +Function: algb +Class: basic +Section: algebras +C-Name: algb +Prototype: mG +Help: algb(al): the element b of the center of the cyclic algebra al used + to define it. +Doc: Given a cyclic algebra $\var{al} = (L/K,\sigma,b)$ output by + \tet{alginit}, returns the element $b\in K$. + \bprog + nf = nfinit(y); + ? p = idealprimedec(nf,7)[1]; + ? p2 = idealprimedec(nf,11)[1]; + ? A = alginit(nf,[3,[[p,p2],[1/3,2/3]],[0]]); + ? algb(A) + %5 = Mod(-77, y) + @eprog + +Function: algbasis +Class: basic +Section: algebras +C-Name: algbasis +Prototype: mG +Help: algbasis(al): basis of the stored order of the central simple algebra al. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns + a $\Z$-basis of the order~${\cal O}_{0}$ stored in \var{al} with respect to the + natural order in \var{al}. It is a maximal order if one has been computed. + \bprog + A = alginit(nfinit(y), [-1,-1]); + ? algbasis(A) + %2 = + [1 0 0 1/2] + + [0 1 0 1/2] + + [0 0 1 1/2] + + [0 0 0 1/2] + @eprog + +Function: algbasistoalg +Class: basic +Section: algebras +C-Name: algbasistoalg +Prototype: GG +Help: algbasistoalg(al,x): transforms the column vector x on the integral + basis of al into an element of al in algebraic form. +Doc: Given an element \var{x} in the central simple algebra \var{al} output + by \tet{alginit}, transforms it to its algebraic representation in \var{al}. + This is the inverse function of \tet{algalgtobasis}. + \bprog + ? A = alginit(nfinit(y^2-5),[2,y]); + ? z = algbasistoalg(A,[0,1,0,0,2,-3,0,0]~); + ? liftall(z) + %3 = [(-1/2*y - 2)*x + (-1/4*y + 5/4), -3/4*y + 7/4]~ + ? algalgtobasis(A,z) + %4 = [0, 1, 0, 0, 2, -3, 0, 0]~ + @eprog + +Function: algcenter +Class: basic +Section: algebras +C-Name: algcenter +Prototype: mG +Help: algcenter(al): center of the algebra al. +Doc: If \var{al} is a table algebra output by \tet{algtableinit}, returns a + basis of the center of the algebra~\var{al} over its prime field ($\Q$ or + $\F_{p}$). If \var{al} is a central simple algebra output by \tet{alginit}, + returns the center of~\var{al}, which is stored in \var{al}. + + A simple example: the $2\times 2$ upper triangular matrices over $\Q$, + generated by $I_{2}$, $a = \kbd{[0,1;0,0]}$ and $b = \kbd{[0,0;0,1]}$, + such that $a^{2} = 0$, $ab = a$, $ba = 0$, $b^{2} = b$: the diagonal matrices + form the center. + \bprog + ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; + ? A = algtableinit(mt); + ? algcenter(A) \\ = (I_2) + %3 = + [1] + + [0] + + [0] + @eprog + + An example in the central simple case: + + \bprog + ? nf = nfinit(y^3-y+1); + ? A = alginit(nf, [-1,-1]); + ? algcenter(A).pol + %3 = y^3 - y + 1 + @eprog + +Function: algcentralproj +Class: basic +Section: algebras +C-Name: alg_centralproj +Prototype: GGD0,L, +Help: algcentralproj(al,z,{maps=0}): projections of the algebra al on the + orthogonal central idempotents z[i]. +Doc: Given a table algebra \var{al} output by \tet{algtableinit} and a + \typ{VEC} $\var{z}=[z_{1},\dots,z_{n}]$ of orthogonal central idempotents, + returns a \typ{VEC} $[al_{1},\dots,al_{n}]$ of algebras such that + $al_{i} = z_{i}\, al$. If $\var{maps}=1$, each $al_{i}$ is a \typ{VEC} + $[quo,proj,lift]$ where \var{quo} is the quotient algebra, \var{proj} is a + \typ{MAT} representing the projection onto this quotient and \var{lift} is a + \typ{MAT} representing a lift. + + A simple example: $\F_{2}\times \F_{4}$, generated by~$1=(1,1)$, $e=(1,0)$ + and~$x$ such that~$x^{2}+x+1=0$. We have~$e^{2}=e$, $x^{2}=x+1$ and~$ex=0$. + \bprog + ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; + ? A = algtableinit(mt,2); + ? e = [0,1,0]~; + ? e2 = algsub(A,[1,0,0]~,e); + ? [a,a2] = algcentralproj(A,[e,e2]); + ? algdim(a) + %6 = 1 + ? algdim(a2) + %7 = 2 + @eprog + +Function: algchar +Class: basic +Section: algebras +C-Name: algchar +Prototype: mG +Help: algchar(al): characteristic of the algebra al. +Doc: Given an algebra \var{al} output by \tet{alginit} or \tet{algtableinit}, + returns the characteristic of \var{al}. + \bprog + ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; + ? A = algtableinit(mt,13); + ? algchar(A) + %3 = 13 + @eprog + +Function: algcharpoly +Class: basic +Section: algebras +C-Name: algcharpoly +Prototype: DGGDnD0,L, +Help: algcharpoly({al},b,{v='x},{abs=0}): (reduced) characteristic polynomial of b in + al (Hamilton quaternions if omitted), with respect to the variable v. +Doc: Given an element $b$ in \var{al} (Hamilton quaternions if omitted), returns + its characteristic polynomial as a polynomial in the variable $v$. If \var{al} + is a table algebra output by \tet{algtableinit} or if $abs=1$, returns the + absolute characteristic polynomial of \var{b}, which is an element of + $\F_{p}[v]$, $\Q[v]$ or~$\R[v]$; if \var{al} is omitted or a central simple + algebra output by \tet{alginit} and $abs=0$, returns the reduced characteristic + polynomial of \var{b}, which is an element of~$K[v]$ where~$K$ is the center of + \var{al}. + \bprog + ? al = alginit(nfinit(y), [-1,-1]); \\ (-1,-1)_Q + ? algcharpoly(al, [0,1]~) + %2 = x^2 + 1 + ? algcharpoly(al, [0,1]~,,1) + %3 = x^4 + 2*x^2 + 1 + ? nf = nfinit(y^2-5); + ? al = alginit(nf,[-1,y]); + ? a = [y,1+x]~*Mod(1,y^2-5)*Mod(1,x^2+1); + ? P = lift(algcharpoly(al,a)) + %7 = x^2 - 2*y*x + (-2*y + 5) + ? algcharpoly(al,a,,1) + %8 = x^8 - 20*x^6 - 80*x^5 + 110*x^4 + 800*x^3 + 1500*x^2 - 400*x + 25 + ? lift(P*subst(P,y,-y)*Mod(1,y^2-5))^2 + %9 = x^8 - 20*x^6 - 80*x^5 + 110*x^4 + 800*x^3 + 1500*x^2 - 400*x + 25 + ? algcharpoly(,[sqrt(2),-1,0,Pi]~) \\ Hamilton quaternions + %10 = x^2 - 2.8284271247*x + 12.8696044010 + @eprog + + Also accepts a square matrix with coefficients in \var{al}. + +Function: algdegree +Class: basic +Section: algebras +C-Name: algdegree +Prototype: lG +Help: algdegree(al): degree of the central simple algebra al. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns + the degree of \var{al}. + \bprog + ? nf = nfinit(y^3-y+1); + ? A = alginit(nf, [-1,-1]); + ? algdegree(A) + %3 = 2 + @eprog + +Function: algdep +Class: basic +Section: linear_algebra +C-Name: algdep0 +Prototype: GLD0,L, +Help: algdep(z,k,{flag=0}): algebraic relations up to degree k of z, using + lindep([1,z,...,z^(k-1)], flag). +Doc: \sidx{algebraic dependence} + $z$ being real/complex, or $p$-adic, finds a polynomial (in the variable + \kbd{'x}) of degree at most + $k$, with integer coefficients, having $z$ as approximate root. Note that the + polynomial which is obtained is not necessarily the ``correct'' one. In fact + it is not even guaranteed to be irreducible. One can check the closeness + either by a polynomial evaluation (use \tet{subst}), or by computing the + roots of the polynomial given by \kbd{algdep} (use \tet{polroots} or + \tet{polrootspadic}). + + Internally, \tet{lindep}$([1,z,\ldots,z^{k}], \fl)$ is used. A nonzero value of + $\fl$ may improve on the default behavior if the input number is known to a + \emph{huge} accuracy, and you suspect the last bits are incorrect: if $\fl > 0$ + the computation is done with an accuracy of $\fl$ decimal digits; to get + meaningful results, the parameter $\fl$ should be smaller than the number of + correct decimal digits in the input. But default values are usually + sufficient, so try without $\fl$ first: + \bprog + ? \p200 + ? z = 2^(1/6)+3^(1/5); + ? algdep(z, 30); \\ right in 63ms + ? algdep(z, 30, 100); \\ wrong in 39ms + ? algdep(z, 30, 170); \\ right in 61ms + ? algdep(z, 30, 200); \\ wrong in 146ms + ? \p250 + ? z = 2^(1/6)+3^(1/5); \\ recompute to new, higher, accuracy ! + ? algdep(z, 30); \\ right in 68ms + ? algdep(z, 30, 200); \\ right in 68ms + ? \p500 + ? algdep(2^(1/6)+3^(1/5), 30); \\ right in 138ms + ? \p1000 + ? algdep(2^(1/6)+3^(1/5), 30); \\ right in 276s + @eprog\noindent + The changes in \kbd{realprecision} only affect the quality of the + initial approximation to $2^{1/6} + 3^{1/5}$, \kbd{algdep} itself uses + exact operations. The size of its operands depend on the accuracy of the + input of course: a more accurate input means slower operations. + + Proceeding by increments of 5 digits of accuracy, \kbd{algdep} with default + flag produces its first correct result at 195 digits, and from then on a + steady stream of correct results: + \bprog + \\ assume T contains the correct result, for comparison + forstep(d=100, 250, 5, \ + localprec(d); \ + print(d, " ", algdep(2^(1/6)+3^(1/5),30) == T)) + @eprog\noindent + This example is the test case studied in a 2000 paper by Borwein and + Lisonek: Applications of integer relation algorithms, \emph{Discrete Math.}, + {\bf 217}, p.~65--82. The version of PARI tested there was 1.39, which + succeeded reliably from precision 265 on, in about 1000 as much time as the + current version (on slower hardware of course). + + Note that this function does not work if $z$ is a power series. The function + \kbd{seralgdep} can be used in this case to find linear relations wich + polynomial coefficients between powers of $z$. +Variant: Also available is \fun{GEN}{algdep}{GEN z, long k} ($\fl=0$). + +Function: algdim +Class: basic +Section: algebras +C-Name: algdim +Prototype: lGD0,L, +Help: algdim(al,{abs=0}): dimension of the algebra al. +Doc: If \var{al} is a table algebra output by \tet{algtableinit} or if~$abs=1$, + returns the dimension of \var{al} over its prime subfield ($\Q$ or $\F_{p}$) or + over $\R$ for real algebras. + If~\var{al} is a central simple algebra output by \tet{alginit} and~$abs=0$, + returns the dimension of \var{al} over its center. + + \bprog + ? nf = nfinit(y^3-y+1); + ? A = alginit(nf, [-1,-1]); + ? algdim(A) + %3 = 4 + ? algdim(A,1) + %4 = 12 + ? C = alginit(I,0); \\ complex numbers as a real algebra + ? algdim(C,1) + %6 = 2 + @eprog + +Function: algdisc +Class: basic +Section: algebras +C-Name: algdisc +Prototype: G +Help: algdisc(al): discriminant of the stored order of the algebra al. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, computes + the discriminant of the order ${\cal O}_{0}$ stored in \var{al}, that is the + determinant of the trace form $\rm{Tr} : {\cal O}_{0}\times {\cal O}_{0} + \to \Z$. + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-3,1-y]); + ? [PR,h] = alghassef(A) + %3 = [[[2, [2, 0]~, 1, 2, 1], [3, [3, 0]~, 1, 2, 1]], Vecsmall([0, 1])] + ? n = algdegree(A); + ? D = algdim(A,1); + ? h = vector(#h, i, n - gcd(n,h[i])); + ? n^D * nf.disc^(n^2) * idealnorm(nf, idealfactorback(nf,PR,h))^n + %4 = 12960000 + ? algdisc(A) + %5 = 12960000 + @eprog + +Function: algdivl +Class: basic +Section: algebras +C-Name: algdivl +Prototype: DGGG +Help: algdivl({al},x,y): element x\y in al (Hamilton quaternions if omitted). +Doc: Given two elements $x$ and $y$ in \var{al} (Hamilton quaternions if + omitted), computes their left quotient $x\backslash y$ in the algebra \var{al}: + an element $z$ such that $xz=y$ (such an element is not unique when $x$ is a + zerodivisor). If~$x$ is invertible, this is the same as $x^{-1}y$. Assumes that + $y$ is left divisible by $x$ (i.e. that $z$ exists). Also accepts square + matrices with coefficients in~\var{al}. + + \bprog + ? A = alginit(nfinit(y),[-1,1]); + ? x = [1,1]~; algisinv(A,x) + % = 0 + ? z = algmul(A,x,algrandom(A,2)) + % = [0, 0, 0, 8]~ + ? algdivl(A,x,z) + % = [4, 4, 0, 0]~ + @eprog + +Function: algdivr +Class: basic +Section: algebras +C-Name: algdivr +Prototype: DGGG +Help: algdivr({al},x,y): element x/y in al (Hamilton quaternions if omitted). +Doc: Given two elements $x$ and $y$ in \var{al} (Hamilton quaternions if + omitted), returns $xy^{-1}$. Also accepts square matrices with coefficients in + \var{al}. + +Function: alggroup +Class: basic +Section: algebras +C-Name: alggroup +Prototype: GDG +Help: alggroup(gal,{p=0}): constructs the group algebra of gal over Q (resp. Fp). +Doc: initializes the group algebra~$K[G]$ over~$K=\Q$ ($p$ omitted) or~$\F_{p}$ + where~$G$ is the underlying group of the \kbd{galoisinit} structure~\var{gal}. + The input~\var{gal} is also allowed to be a \typ{VEC} of permutations that is + closed under products. + + Example: + \bprog + ? K = nfsplitting(x^3-x+1); + ? gal = galoisinit(K); + ? al = alggroup(gal); + ? algissemisimple(al) + %4 = 1 + ? G = [Vecsmall([1,2,3]), Vecsmall([1,3,2])]; + ? al2 = alggroup(G, 2); + ? algissemisimple(al2) + %8 = 0 + @eprog + +Function: alggroupcenter +Class: basic +Section: algebras +C-Name: alggroupcenter +Prototype: GDGD& +Help: alggroupcenter(gal,{p=0},{&cc}): constructs the center of the group + algebra of gal over Q (resp. Fp), and sets cc to the conjugacy classes of gal. +Doc: initializes the center~$Z(K[G])$ of the group algebra~$K[G]$ over~$K=\Q$ + ($p = 0$ or omitted) or~$\F_{p}$ where~$G$ is the underlying group of the + \kbd{galoisinit} structure~\var{gal}. The input~\var{gal} is also allowed to + be a \typ{VEC} of permutations that is closed under products. + Sets~\var{cc} to a \typ{VEC}~$[\var{elts},\var{conjclass},\var{rep},\var{flag}]$ + where~\var{elts} is a sorted \typ{VEC} containing the list of elements + of~$G$, \var{conjclass} is a \typ{VECSMALL} of the same length as~\var{elts} + containing the index of the conjugacy class of the corresponding element (an + integer between $1$ and the number of conjugacy classes), and~\var{rep} is a + \typ{VECSMALL} of length the number of conjugacy classes giving for each + conjugacy class the index in~\var{elts} of a representative of this conjugacy + class. Finally \var{flag} is $1$ if and only if the permutation + representation of $G$ is transitive, in which case the $i$-th element + of \var{elts} is characterized by $g[1] = i$; this is always the case + when \var{gal} is a \kbd{galoisinit} structure. The basis of~$Z(K[G])$ as + output consists of the indicator functions of the conjugacy classes in the + ordering given by~\var{cc}. Example: + \bprog + ? K = nfsplitting(x^4+x+1); + ? gal = galoisinit(K); \\ S4 + ? al = alggroupcenter(gal,,&cc); + ? algiscommutative(al) + %4 = 1 + ? #cc[3] \\ number of conjugacy classes of S4 + %5 = 5 + ? gal = [Vecsmall([1,2,3]),Vecsmall([1,3,2])]; \\ C2 + ? al = alggroupcenter(gal,,&cc); + ? cc[3] + %8 = Vecsmall([1, 2]) + ? cc[4] + %9 = 0 + @eprog + +Function: alghasse +Class: basic +Section: algebras +C-Name: alghasse +Prototype: GDG +Help: alghasse(al,{pl}): the hasse invariant of the central simple algebra al at + the place pl. +Doc: Given a central simple algebra \var{al} output by \tet{alginit} and a prime + ideal or an integer between $1$ and $r_{1}+r_{2}$, returns a \typ{FRAC} $h$ : the + local Hasse invariant of \var{al} at the place specified by \var{pl}. + If \var{al} is an algebra over $\R$, returns the Hasse invariant of \var{al} + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-1,y]); + ? alghasse(A, 1) + %3 = 1/2 + ? alghasse(A, 2) + %4 = 0 + ? alghasse(A, idealprimedec(nf,2)[1]) + %5 = 1/2 + ? alghasse(A, idealprimedec(nf,5)[1]) + %6 = 0 + ? H = alginit(1.,1/2); \\ Hamilton quaternion algebra + ? alghasse(H) + %8 = 1/2 + @eprog + +Function: alghassef +Class: basic +Section: algebras +C-Name: alghassef +Prototype: mG +Help: alghassef(al): the hasse invariant of the central simple algebra al at finite places. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns + a \typ{VEC} $[\kbd{PR}, h_{f}]$ describing the local Hasse invariants at the + finite places of the center: \kbd{PR} is a \typ{VEC} of primes and $h_{f}$ is a + \typ{VECSMALL} of integers modulo the degree $d$ of \var{al}. The Hasse + invariant of~\var{al} at the primes outside~\kbd{PR} is~$0$, but~\kbd{PR} can + include primes at which the Hasse invariant is~$0$. + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-1,2*y-1]); + ? [PR,hf] = alghassef(A); + ? PR + %4 = [[19, [10, 2]~, 1, 1, [-8, 2; 2, -10]], [2, [2, 0]~, 1, 2, 1]] + ? hf + %5 = Vecsmall([1, 0]) + @eprog + +Function: alghassei +Class: basic +Section: algebras +C-Name: alghassei +Prototype: mG +Help: alghassei(al): the hasse invariant of the central simple algebra al + at infinite places. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns + a \typ{VECSMALL} $h_{i}$ of $r_{1}$ integers modulo the degree $d$ of \var{al}, + where $r_{1}$ is the number of real places of the center: the local Hasse + invariants of \var{al} at infinite places. + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-1,y]); + ? alghassei(A) + %3 = Vecsmall([1, 0]) + @eprog + +Function: algindex +Class: basic +Section: algebras +C-Name: algindex +Prototype: lGDG +Help: algindex(al,{pl}): the index of the central simple algebra al. If pl is + set, it should be a prime ideal of the center or an integer between 1 and + r1+r2, and in that case return the local index at the place pl instead. +Doc: Returns the index of the central simple algebra~$A$ over~$K$ (as output by + alginit), that is the degree~$e$ of the unique central division algebra~$D$ + over $K$ such that~$A$ is isomorphic to some matrix algebra~$M_{k}(D)$. If + \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ + and~$r_{1}+r_{2}$, and in that case return the local index at the place + \var{pl} instead. + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-1,y]); + ? algindex(A, 1) + %3 = 2 + ? algindex(A, 2) + %4 = 1 + ? algindex(A, idealprimedec(nf,2)[1]) + %5 = 2 + ? algindex(A, idealprimedec(nf,5)[1]) + %6 = 1 + ? algindex(A) + %7 = 2 + @eprog + +Function: alginit +Class: basic +Section: algebras +C-Name: alginit +Prototype: GGDnD3,L, +Help: alginit(B,C,{v},{flag=3}): initializes the central simple algebra + defined by data B, C. Binary digits of the flag mean 1: compute a maximal + order; 2: fully factor the discriminant instead of using a lazy factorisation. +Doc: initializes the central simple algebra defined by data $B$, $C$ and + variable $v$, as follows. + + \item (multiplication table) $B$ is the base number field $K$ in \tet{nfinit} + form, $C$ is a ``multiplication table'' over $K$. + As a $K$-vector space, the algebra is generated by a basis + $(e_{1} = 1,\dots, e_{n})$; the table is given as a \typ{VEC} of $n$ matrices + in $M_{n}(K)$, giving the left multiplication by the basis elements~$e_{i}$, + in the given basis. + Assumes that $e_{1}= 1$, that the multiplication table is integral, and that + $(\bigoplus_{i=1}^{n}K e_{i},C)$ describes a central simple algebra over $K$. + \bprog + { mi = [0,-1,0, 0; + 1, 0,0, 0; + 0, 0,0,-1; + 0, 0,1, 0]; + mj = [0, 0,-1,0; + 0, 0, 0,1; + 1, 0, 0,0; + 0,-1, 0,0]; + mk = [0, 0, 0, -1; + 0, 0,-1, 0; + 0, 1, 0, 0; + 1, 0, 0, 0]; + A = alginit(nfinit(y), [matid(4), mi,mj,mk], , 0); } + @eprog represents (in a complicated way) the quaternion algebra $(-1,-1)_{\Q}$. + See below for a simpler solution. + + \item (cyclic algebra) $B$ is an \kbd{rnf} structure attached to a cyclic + number field extension $L/K$ of degree $d$, $C$ is a \typ{VEC} + \kbd{[sigma,b]} with 2 components: \kbd{sigma} is a \typ{POLMOD} representing + an automorphism generating $\text{Gal}(L/K)$, $b$ is an element in $K^{*}$. + This represents the cyclic algebra~$(L/K,\sigma,b)$. Currently the element + $b$ has to be integral. + \bprog + ? Q = nfinit(y); T = polcyclo(5, 'x); F = rnfinit(Q, T); + ? A = alginit(F, [Mod(x^2,T), 3]); + @eprog defines the cyclic algebra $(L/\Q, \sigma, 3)$, where + $L = \Q(\zeta_{5})$ and $\sigma:\zeta\mapsto\zeta^{2}$ generates + $\text{Gal}(L/\Q)$. + + \item (quaternion algebra, special case of the above) $B$ is an \kbd{nf} + structure attached to a number field $K$, $C = [a,b]$ is a vector + containing two elements of $K^{*}$ with $a$ not a square in $K$, returns the + quaternion algebra $(a,b)_{K}$. + The variable $v$ (\kbd{'x} by default) must have higher priority than the + variable of $K$\kbd{.pol} and is used to represent elements in the splitting + field $L = K[x]/(x^{2}-a)$. + \bprog + ? Q = nfinit(y); A = alginit(Q, [-1,-1]); \\@com $(-1,-1)_{\Q}$ + @eprog + + \item (algebra/$K$ defined by local Hasse invariants) + $B$ is an \kbd{nf} structure attached to a number field $K$, + $C = [d, [\kbd{PR},h_{f}], h_{i}]$ is a triple + containing an integer $d > 1$, a pair $[\kbd{PR}, h_{f}]$ describing the + Hasse invariants at finite places, and $h_{i}$ the Hasse invariants + at archimedean (real) places. A local Hasse invariant belongs to $(1/d)\Z/\Z + \subset \Q/\Z$, and is given either as a \typ{FRAC} (lift to $(1/d)\Z$), + a \typ{INT} or \typ{INTMOD} modulo $d$ (lift to $\Z/d\Z$); a whole vector + of local invariants can also be given as a \typ{VECSMALL}, whose + entries are handled as \typ{INT}s. \kbd{PR} is a list of prime ideals + (\kbd{prid} structures), and $h_{f}$ is a vector of the same length giving the + local invariants at those maximal ideals. The invariants at infinite real + places are indexed by the real roots $K$\kbd{.roots}: if the Archimedean + place $v$ is attached to the $j$-th root, the value of + $h_{v}$ is given by $h_{i}[j]$, must be $0$ or $1/2$ (or~$d/2$ modulo~$d$), and + can be nonzero only if~$d$ is even. + + By class field theory, provided the local invariants $h_{v}$ sum to $0$, up + to Brauer equivalence, there is a unique central simple algebra over $K$ + with given local invariants and trivial invariant elsewhere. In particular, + up to isomorphism, there is a unique such algebra $A$ of degree $d$. + + We realize $A$ as a cyclic algebra through class field theory. The variable $v$ + (\kbd{'x} by default) must have higher priority than the variable of + $K$\kbd{.pol} and is used to represent elements in the (cyclic) splitting + field extension $L/K$ for $A$. + + \bprog + ? nf = nfinit(y^2+1); + ? PR = idealprimedec(nf,5); #PR + %2 = 2 + ? hi = []; + ? hf = [PR, [1/3,-1/3]]; + ? A = alginit(nf, [3,hf,hi]); + ? algsplittingfield(A).pol + %6 = x^3 - 21*x + 7 + @eprog + + \item (matrix algebra, toy example) $B$ is an \kbd{nf} structure attached + to a number field $K$, $C = d$ is a positive integer. Returns a cyclic + algebra isomorphic to the matrix algebra $M_{d}(K)$. + + \item (algebras over~$\R$) If $B$ is a \typ{REAL} and $C = 1/2$, returns + a structure representing the Hamilton quaternion algebra~${\bf H} = + (-1,-1)_{\R}$. If $B$ is a \typ{REAL} and $C = 0$, returns an algebra structure + representing~$\R$. If $B$ is a \typ{COMPLEX} and $C = 0$, returns an algebra + structure representing~$\C$. + + In all cases over a number field, this function factors various discriminants + and computes a maximal order for the algebra by default, which may require a + lot of time. This can be controlled by $\fl$, whose binary digits mean: + + \item $1$: compute a maximal order. + + \item $2$: fully factor the discriminants instead of using a lazy + factorisation. If this digit of $\fl$ is set to~$0$, the local Hasse invariants + are not computed. + + If only a partial factorisation is known, the computed order is only guaranteed + to be maximal at the known prime factors. + + The pari object representing such an algebra $A$ is a \typ{VEC} with the + following data: + + \item A splitting field $L$ of $A$ of the same degree over $K$ as $A$, in + \kbd{rnfinit} format, accessed with \kbd{algsplittingfield}. + + \item The Hasse invariants at the real places of $K$, accessed with + \kbd{alghassei}. + + \item The Hasse invariants of $A$ at the finite primes of $K$ that ramify in + the natural order of $A$, accessed with \kbd{alghassef}. + + \item A basis of an order ${\cal O}_{0}$ expressed on the basis of the natural + order, accessed with \kbd{algbasis}. + + \item A basis of the natural order expressed on the basis of ${\cal O}_{0}$, + accessed with \kbd{alginvbasis}. + + \item The left multiplication table of ${\cal O}_{0}$ on the previous basis, + accessed with \kbd{algmultable}. + + \item The characteristic of $A$ (always $0$), accessed with \kbd{algchar}. + + \item The absolute traces of the elements of the basis of ${\cal O}_{0}$. + + \item If $A$ was constructed as a cyclic algebra~$(L/K,\sigma,b)$ of degree + $d$, a \typ{VEC} $[\sigma,\sigma^{2},\dots,\sigma^{d-1}]$. The function + \kbd{algaut} returns $\sigma$. + + \item If $A$ was constructed as a cyclic algebra~$(L/K,\sigma,b)$, the + element $b$, accessed with \kbd{algb}. + + \item If $A$ was constructed with its multiplication table $mt$ over $K$, + the \typ{VEC} of \typ{MAT} $mt$, accessed with \kbd{algrelmultable}. + + \item If $A$ was constructed with its multiplication table $mt$ over $K$, + a \typ{VEC} with three components: a \typ{COL} representing an element of $A$ + generating the splitting field $L$ as a maximal subfield of $A$, a \typ{MAT} + representing an $L$-basis ${\cal B}$ of $A$ expressed on the $\Z$-basis of + ${\cal O}_{0}$, and a \typ{MAT} representing the $\Z$-basis of ${\cal O}_{0}$ + expressed on ${\cal B}$. This data is accessed with \kbd{algsplittingdata}. + +Function: alginv +Class: basic +Section: algebras +C-Name: alginv +Prototype: DGG +Help: alginv({al},x): element 1/x in al (Hamilton quaternions if omitted). +Doc: Given an element $x$ in \var{al} (Hamilton quaternions if omitted), + computes its inverse $x^{-1}$ in the algebra \var{al}. Assumes that $x$ is + invertible. + \bprog + ? A = alginit(nfinit(y), [-1,-1]); + ? alginv(A,[1,1,0,0]~) + %2 = [1/2, 1/2, 0, 0]~ + ? alginv(,[1,0,Pi,sqrt(2)]~) \\ Hamilton quaternions + %3 = [0.0777024661, 0, -0.2441094967, -0.1098878814]~ + @eprog + + Also accepts square matrices with coefficients in \var{al}. + +Function: alginvbasis +Class: basic +Section: algebras +C-Name: alginvbasis +Prototype: mG +Help: alginvbasis(al): basis of the natural order of the central simple algebra + al in terms of the stored order. +Doc: Given an central simple algebra \var{al} output by \tet{alginit}, returns + a $\Z$-basis of the natural order in \var{al} with respect to the + order~${\cal O}_{0}$ stored in \var{al}. + \bprog + A = alginit(nfinit(y), [-1,-1]); + ? alginvbasis(A) + %2 = + [1 0 0 -1] + + [0 1 0 -1] + + [0 0 1 -1] + + [0 0 0 2] + @eprog + +Function: algisassociative +Class: basic +Section: algebras +C-Name: algisassociative +Prototype: iGD0,G, +Help: algisassociative(mt,p=0): true (1) if the multiplication table mt is + suitable for algtableinit(mt,p), false (0) otherwise. +Doc: Returns 1 if the multiplication table \kbd{mt} is suitable for + \kbd{algtableinit(mt,p)}, 0 otherwise. More precisely, \kbd{mt} should be + a \typ{VEC} of $n$ matrices in $M_{n}(K)$, giving the left multiplications + by the basis elements $e_{1}, \dots, e_{n}$ (structure constants). + We check whether the first basis element $e_{1}$ is $1$ and + $e_{i}(e_{j}e_{k}) = (e_{i}e_{j})e_{k}$ for all $i,j,k$. + \bprog + ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; + ? algisassociative(mt) + %2 = 1 + @eprog + May be used to check a posteriori an algebra: we also allow \kbd{mt} as + output by \tet{algtableinit} ($p$ is ignored in this case). + +Function: algiscommutative +Class: basic +Section: algebras +C-Name: algiscommutative +Prototype: iG +Help: algiscommutative(al): test whether the algebra al is commutative. +Doc: \var{al} being a table algebra output by \tet{algtableinit} or a central + simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is + commutative. + \bprog + ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; + ? A = algtableinit(mt); + ? algiscommutative(A) + %3 = 0 + ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; + ? A = algtableinit(mt,2); + ? algiscommutative(A) + %6 = 1 + @eprog + +Function: algisdivision +Class: basic +Section: algebras +C-Name: algisdivision +Prototype: iGDG +Help: algisdivision(al,{pl}): tests whether the central simple algebra al is a + division algebra. If pl is set, it should be a prime ideal of the center or an + integer between 1 and r1+r2, and in that case tests whether al is locally a + division algebra at the place pl instead. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, tests + whether \var{al} is a division algebra. If \var{pl} is set, it should be a + prime ideal of~$K$ or an integer between~$1$ and~$r_{1}+r_{2}$, and in that + case tests whether \var{al} is locally a division algebra at the place + \var{pl} instead. + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-1,y]); + ? algisdivision(A, 1) + %3 = 1 + ? algisdivision(A, 2) + %4 = 0 + ? algisdivision(A, idealprimedec(nf,2)[1]) + %5 = 1 + ? algisdivision(A, idealprimedec(nf,5)[1]) + %6 = 0 + ? algisdivision(A) + %7 = 1 + @eprog + +Function: algisdivl +Class: basic +Section: algebras +C-Name: algisdivl +Prototype: iDGGGD& +Help: algisdivl({al},x,y,{&z}): tests whether y is left divisible by x and sets + z to the left quotient x\y. +Doc: Given two elements $x$ and $y$ in \var{al} (Hamilton quaternions if + omitted), tests whether $y$ is left divisible by $x$, that is whether there + exists~$z$ in \var{al} such that~$xz=y$, and sets $z$ to this element if it + exists. + \bprog + ? A = alginit(nfinit(y), [-1,1]); + ? algisdivl(A,[x+2,-x-2]~,[x,1]~) + %2 = 0 + ? algisdivl(A,[x+2,-x-2]~,[-x,x]~,&z) + %3 = 1 + ? z + %4 = [Mod(-2/5*x - 1/5, x^2 + 1), 0]~ + @eprog + + Also accepts square matrices with coefficients in \var{al}. + +Function: algisinv +Class: basic +Section: algebras +C-Name: algisinv +Prototype: iDGGD& +Help: algisinv({al},x,{&ix}): tests whether x is invertible in al (Hamilton + quaternions if omitted) and sets ix to the inverse of x. +Doc: Given an element $x$ in \var{al} (Hamilton quaternions if omitted), tests + whether $x$ is invertible, and sets $ix$ to the inverse of $x$. + \bprog + ? A = alginit(nfinit(y), [-1,1]); + ? algisinv(A,[-1,1]~) + %2 = 0 + ? algisinv(A,[1,2]~,&ix) + %3 = 1 + ? ix + %4 = [Mod(Mod(-1/3, y), x^2 + 1), Mod(Mod(2/3, y), x^2 + 1)]~ + @eprog + + Also accepts square matrices with coefficients in \var{al}. + +Function: algisramified +Class: basic +Section: algebras +C-Name: algisramified +Prototype: iGDG +Help: algisramified(al,{pl}): tests whether the central simple algebra al is + ramified, i.e. not isomorphic to a matrix ring over its center. If pl is set, + it should be a prime ideal of the center or an integer between 1 and r1+r2, and + in that case tests whether al is locally ramified at the place pl instead. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, tests + whether \var{al} is ramified, i.e. not isomorphic to a matrix algebra over its + center. If \var{pl} is set, it should be a prime ideal of~$K$ or an integer + between~$1$ and~$r_{1}+r_{2}$, and in that case tests whether \var{al} is + locally ramified at the place \var{pl} instead. + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-1,y]); + ? algisramified(A, 1) + %3 = 1 + ? algisramified(A, 2) + %4 = 0 + ? algisramified(A, idealprimedec(nf,2)[1]) + %5 = 1 + ? algisramified(A, idealprimedec(nf,5)[1]) + %6 = 0 + ? algisramified(A) + %7 = 1 + @eprog + +Function: algissemisimple +Class: basic +Section: algebras +C-Name: algissemisimple +Prototype: iG +Help: algissemisimple(al): test whether the algebra al is semisimple. +Doc: \var{al} being a table algebra output by \tet{algtableinit} or a central + simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is + semisimple. + \bprog + ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; + ? A = algtableinit(mt); + ? algissemisimple(A) + %3 = 0 + ? m_i=[0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; \\ quaternion algebra (-1,-1) + ? m_j=[0,0,-1,0;0,0,0,1;1,0,0,0;0,-1,0,0]; + ? m_k=[0,0,0,-1;0,0,-1,0;0,1,0,0;1,0,0,0]; + ? mt = [matid(4), m_i, m_j, m_k]; + ? A = algtableinit(mt); + ? algissemisimple(A) + %9 = 1 + @eprog + +Function: algissimple +Class: basic +Section: algebras +C-Name: algissimple +Prototype: iGD0,L, +Help: algissimple(al,{ss=0}): test whether the algebra al is simple. +Doc: \var{al} being a table algebra output by \tet{algtableinit} or a central + simple algebra output by \tet{alginit}, tests whether the algebra \var{al} is + simple. If $\var{ss}=1$, assumes that the algebra~\var{al} is semisimple + without testing it. + \bprog + ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; + ? A = algtableinit(mt); \\ matrices [*,*; 0,*] + ? algissimple(A) + %3 = 0 + ? algissimple(A,1) \\ incorrectly assume that A is semisimple + %4 = 1 + ? m_i=[0,-1,0,0;1,0,0,0;0,0,0,-1;0,0,1,0]; + ? m_j=[0,0,-1,0;0,0,0,1;1,0,0,0;0,-1,0,0]; + ? m_k=[0,0,0,-1;0,0,b,0;0,1,0,0;1,0,0,0]; + ? mt = [matid(4), m_i, m_j, m_k]; + ? A = algtableinit(mt); \\ quaternion algebra (-1,-1) + ? algissimple(A) + %10 = 1 + ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; + ? A = algtableinit(mt,2); \\ direct product F_4 x F_2 + ? algissimple(A) + %13 = 0 + @eprog + +Function: algissplit +Class: basic +Section: algebras +C-Name: algissplit +Prototype: iGDG +Help: algissplit(al,{pl}): tests whether the central simple algebra al is + split, i.e. isomorphic to a matrix ring over its center. If pl is set, it + should be a prime ideal of the center or an integer between 1 and r1+r2, and in + that case tests whether al is locally split at the place pl instead. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, tests + whether~\var{al} is split, i.e. isomorphic to a matrix algebra over its center. + If \var{pl} is set, it should be a prime ideal of~$K$ or an integer between~$1$ + and~$r_{1}+r_{2}$, and in that case tests whether \var{al} is locally split + at the place \var{pl} instead. + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-1,y]); + ? algissplit(A, 1) + %3 = 0 + ? algissplit(A, 2) + %4 = 1 + ? algissplit(A, idealprimedec(nf,2)[1]) + %5 = 0 + ? algissplit(A, idealprimedec(nf,5)[1]) + %6 = 1 + ? algissplit(A) + %7 = 0 + @eprog + +Function: alglatadd +Class: basic +Section: algebras +C-Name: alglatadd +Prototype: GGGD& +Help: alglatadd(al,lat1,lat2,{&ptinter}): the sum of the lattices lat1 + and lat2. If ptinter is present, set it to the intersection of the lattices. +Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} + in~\var{al}, computes the sum~$lat1 + lat2$. If \var{ptinter} is + present, set it to the intersection~$lat1 \cap lat2$. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); + ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); + ? latsum = alglatadd(al,lat1,lat2,&latinter); + ? matdet(latsum[1]) + %5 = 4 + ? matdet(latinter[1]) + %6 = 64 + @eprog + +Function: alglatcontains +Class: basic +Section: algebras +C-Name: alglatcontains +Prototype: iGGGD& +Help: alglatcontains(al,lat,x,{&ptc}): tests whether the lattice lat contains the + element x. If ptc is present, sets it to the coordinates of x on the basis of + lat. +Doc: Given an algebra \var{al}, a lattice \var{lat} and \var{x} in~\var{al}, + tests whether~$x\in lat$. If~\var{ptc} is present, sets it to the~\typ{COL} of + coordinates of~$x$ in the basis of~\var{lat}. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? a1 = [1,-1,0,1,2,0,1,2]~; + ? lat1 = alglathnf(al,a1); + ? alglatcontains(al,lat1,a1,&c) + %4 = 1 + ? c + %5 = [-1, -2, -1, 1, 2, 0, 1, 1]~ + @eprog + +Function: alglatelement +Class: basic +Section: algebras +C-Name: alglatelement +Prototype: GGG +Help: alglatelement(al,lat,c): returns the element of al whose coordinates on + the Z-basis of lat are c. +Doc: Given an algebra \var{al}, a lattice \var{lat} and a~\typ{COL}~\var{c}, + returns the element of~\var{al} whose coordinates on the \Z-basis of~\var{lat} + are given by~\var{c}. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? a1 = [1,-1,0,1,2,0,1,2]~; + ? lat1 = alglathnf(al,a1); + ? c = [1..8]~; + ? elt = alglatelement(al,lat1,c); + ? alglatcontains(al,lat1,elt,&c2) + %6 = 1 + ? c==c2 + %7 = 1 + @eprog + +Function: alglathnf +Class: basic +Section: algebras +C-Name: alglathnf +Prototype: GGD0,G, +Help: alglathnf(al,m,{d=0}): the lattice generated by the columns of m, assuming + that this lattice contains d times the integral basis of al. +Doc: Given an algebra \var{al} and a matrix \var{m} with columns representing + elements of \var{al}, returns the lattice $L$ generated by the columns of + \var{m}. If provided, \var{d} must be a rational number such that $L$ contains + \var{d} times the natural basis of~\var{al}. The argument \var{m} is also + allowed to be a \typ{VEC} of \typ{MAT}, in which case \var{m} is replaced by + the concatenation of the matrices, or a \typ{COL}, in which case \var{m} is + replaced by its left multiplication table as an element of \var{al}. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? a = [1,1,-1/2,1,1/3,-1,1,1]~; + ? mt = algtomatrix(al,a,1); + ? lat = alglathnf(al,mt); + ? lat[2] + %5 = 1/6 + @eprog + +Function: alglatindex +Class: basic +Section: algebras +C-Name: alglatindex +Prototype: GGG +Help: alglatindex(al,lat1,lat2): the generalized index (lat2:lat1). +Doc: Given an algebra~\var{al} and two lattices~\var{lat1} and~\var{lat2} + in~\var{al}, computes the generalized index of~\var{lat1} relative + to~\var{lat2}, i.e.~$|lat2/lat1\cap lat2|/|lat1/lat1\cap lat2|$. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); + ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); + ? alglatindex(al,lat1,lat2) + %4 = 1 + ? lat1==lat2 + %5 = 0 + @eprog + +Function: alglatinter +Class: basic +Section: algebras +C-Name: alglatinter +Prototype: GGGD& +Help: alglatinter(al,lat1,lat2,{&ptsum}): the intersection of the lattices lat1 + and lat2. If ptsum is present, sets it to the sum of the lattices. +Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} + in~\var{al}, computes the intersection~$lat1\cap lat2$. If \var{ptsum} is + present, sets it to the sum~$lat1 + lat2$. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); + ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); + ? latinter = alglatinter(al,lat1,lat2,&latsum); + ? matdet(latsum[1]) + %5 = 4 + ? matdet(latinter[1]) + %6 = 64 + @eprog + +Function: alglatlefttransporter +Class: basic +Section: algebras +C-Name: alglatlefttransporter +Prototype: GGG +Help: alglatlefttransporter(al,lat1,lat2): the set of x in al such that x*lat1 + is contained in lat2. +Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} + in~\var{al}, computes the left transporter from \var{lat1} to~\var{lat2}, i.e. + the set of~$x\in al$ such that~$x\cdot lat1 \subset lat2$. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? lat1 = alglathnf(al,[1,-1,0,1,2,0,5,2]~); + ? lat2 = alglathnf(al,[0,1,-2,-1,0,0,3,1]~); + ? tr = alglatlefttransporter(al,lat1,lat2); + ? a = alglatelement(al,tr,[0,0,0,0,0,0,1,0]~); + ? alglatsubset(al,alglatmul(al,a,lat1),lat2) + %6 = 1 + ? alglatsubset(al,alglatmul(al,lat1,a),lat2) + %7 = 0 + @eprog + +Function: alglatmul +Class: basic +Section: algebras +C-Name: alglatmul +Prototype: GGG +Help: alglatmul(al,lat1,lat2): the lattice generated by the products of elements + of lat1 and lat2. +Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} + in~\var{al}, computes the lattice generated by the products of elements + of~\var{lat1} and~\var{lat2}. + One of \var{lat1} and \var{lat2} is also allowed to be an element of~\var{al}; + in this case, computes the product of the element and the lattice. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? a1 = [1,-1,0,1,2,0,1,2]~; + ? a2 = [0,1,2,-1,0,0,3,1]~; + ? lat1 = alglathnf(al,a1); + ? lat2 = alglathnf(al,a2); + ? lat3 = alglatmul(al,lat1,lat2); + ? matdet(lat3[1]) + %7 = 29584 + ? lat3 == alglathnf(al, algmul(al,a1,a2)) + %8 = 0 + ? lat3 == alglatmul(al, lat1, a2) + %9 = 0 + ? lat3 == alglatmul(al, a1, lat2) + %10 = 0 + @eprog + +Function: alglatrighttransporter +Class: basic +Section: algebras +C-Name: alglatrighttransporter +Prototype: GGG +Help: alglatrighttransporter(al,lat1,lat2): the set of x in al such that lat1*x + is contained in lat2. +Doc: Given an algebra \var{al} and two lattices \var{lat1} and \var{lat2} + in~\var{al}, computes the right transporter from \var{lat1} to~\var{lat2}, i.e. + the set of~$x\in al$ such that~$lat1\cdot x \subset lat2$. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? lat1 = alglathnf(al,matdiagonal([1,3,7,1,2,8,5,2])); + ? lat2 = alglathnf(al,matdiagonal([5,3,8,1,9,8,7,1])); + ? tr = alglatrighttransporter(al,lat1,lat2); + ? a = alglatelement(al,tr,[0,0,0,0,0,0,0,1]~); + ? alglatsubset(al,alglatmul(al,lat1,a),lat2) + %6 = 1 + ? alglatsubset(al,alglatmul(al,a,lat1),lat2) + %7 = 0 + @eprog + +Function: alglatsubset +Class: basic +Section: algebras +C-Name: alglatsubset +Prototype: iGGGD& +Help: alglatsubset(al,lat1,lat2,{&ptindex}): tests whether lat1 is contained in + lat2 and if true and ptindex is present, sets it to the index (lat2:lat1). +Doc: Given an algebra~\var{al} and two lattices~\var{lat1} and~\var{lat2} + in~\var{al}, tests whether~$lat1\subset lat2$. If it is true and \var{ptindex} + is present, sets it to the index of~\var{lat1} in~\var{lat2}. + \bprog + ? al = alginit(nfinit(y^2+7), [-1,-1]); + ? lat1 = alglathnf(al,[1,1,0,0,0,0,0,0]~); + ? lat2 = alglathnf(al,[1,0,1,0,0,0,0,0]~); + ? alglatsubset(al,lat1,lat2) + %4 = 0 + ? latsum = alglatadd(al,lat1,lat2); + ? alglatsubset(al,lat1,latsum,&index) + %6 = 1 + ? index + %7 = 4 + @eprog + +Function: algmakeintegral +Class: basic +Section: algebras +C-Name: algmakeintegral +Prototype: GD0,L, +Help: algmakeintegral(mt,{maps=0}): computes an integral multiplication table + for an isomorphic algebra. +Doc: \var{mt} being a multiplication table over $\Q$ in the same format as the + input of \tet{algtableinit}, computes an integral multiplication table + \var{mt2} for an isomorphic algebra. When $\var{maps}=1$, returns a \typ{VEC} + $[\var{mt2},\var{S},\var{T}]$ where \var{S} and \var{T} are matrices + respectively representing the map from the algebra defined by \var{mt} to the + one defined by \var{mt2} and its inverse. + \bprog + ? mt = [matid(2),[0,-1/4;1,0]]; + ? algtableinit(mt); + *** at top-level: algtableinit(mt) + *** ^---------------- + *** algtableinit: domain error in algtableinit: denominator(mt) != 1 + ? mt2 = algmakeintegral(mt); + ? al = algtableinit(mt2); + ? algisassociative(al) + %4 = 1 + ? [mt2, S, T] = algmakeintegral(mt,1); + ? S + %6 = + [1 0] + + [0 1/4] + ? T + %7 = + [1 0] + + [0 4] + ? vector(#mt, i, S * (mt * T[,i]) * T) == mt2 + %8 = 1 + @eprog + +Function: algmul +Class: basic +Section: algebras +C-Name: algmul +Prototype: DGGG +Help: algmul({al},x,y): element x*y in al (Hamilton quaternions if omitted). +Doc: Given two elements $x$ and $y$ in \var{al} (Hamilton quaternions if + omitted), computes their product $xy$ in the algebra~\var{al}. + \bprog + ? A = alginit(nfinit(y), [-1,-1]); + ? algmul(A,[1,1,0,0]~,[0,0,2,1]~) + % = [2, 3, 5, -4]~ + ? algmul(,[1,2,3,4]~,sqrt(I)) \\ Hamilton quaternions + % = [-0.7071067811, 2.1213203435, 4.9497474683, 0.7071067811]~ + @eprog + + Also accepts matrices with coefficients in \var{al}. + +Function: algmultable +Class: basic +Section: algebras +C-Name: algmultable +Prototype: mG +Help: algmultable(al): multiplication table of al over its prime subfield. +Doc: + returns a multiplication table of \var{al} over its + prime subfield ($\Q$ or $\F_{p}$) or over~$\R$ for real algebras, as a + \typ{VEC} of \typ{MAT}: the left multiplication tables of basis elements. + If \var{al} was output by \tet{algtableinit}, returns the multiplication + table used to define \var{al}. + If \var{al} was output by \tet{alginit}, returns the multiplication table of + the order~${\cal O}_{0}$ stored in \var{al}. + \bprog + ? A = alginit(nfinit(y), [-1,-1]); + ? M = algmultable(A); + ? #M + %3 = 4 + ? M[1] \\ multiplication by e_1 = 1 + %4 = + [1 0 0 0] + + [0 1 0 0] + + [0 0 1 0] + + [0 0 0 1] + + ? M[2] + %5 = + [0 -1 1 0] + + [1 0 1 1] + + [0 0 1 1] + + [0 0 -2 -1] + ? H = alginit(1.,1/2); \\ Hamilton quaternions + ? algmultable(H)[3] \\ multiplication by j + %7 = + [0 0 -1 0] + + [0 0 0 1] + + [1 0 0 0] + + [0 -1 0 0] + @eprog + +Function: algneg +Class: basic +Section: algebras +C-Name: algneg +Prototype: DGG +Help: algneg({al},x): element -x in al (Hamilton quaternions if omitted). +Doc: Given an element $x$ in \var{al}, computes its opposite $-x$ in the + algebra \var{al} (Hamilton quaternions if omitted). + \bprog + ? A = alginit(nfinit(y), [-1,-1]); + ? algneg(A,[1,1,0,0]~) + %2 = [-1, -1, 0, 0]~ + @eprog + + Also accepts matrices with coefficients in \var{al}. + +Function: algnorm +Class: basic +Section: algebras +C-Name: algnorm +Prototype: DGGD0,L, +Help: algnorm({al},x,{abs=0}): (reduced) norm of x. +Doc: Given an element \var{x} in \var{al} (Hamilton quaternions if omitted), + computes its norm. If \var{al} is a table algebra output by \tet{algtableinit} + or if $abs=1$, returns the absolute norm of \var{x}, which is an element of + $\F_{p}$, $\Q$ or~$\R$; if \var{al} is omitted or a central simple algebra + output by \tet{alginit} and $abs=0$ (default), returns the reduced norm of + \var{x}, which is an element of the center of \var{al}. + \bprog + ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; + ? A = algtableinit(mt,19); + ? algnorm(A,[0,-2,3]~) + %3 = 18 + ? nf = nfinit(y^2-5); + ? B = alginit(nf,[-1,y]); + ? b = [x,1]~; + ? n = algnorm(B,b) + %7 = Mod(-y + 1, y^2 - 5) + ? algnorm(B,b,1) + %8 = 16 + ? nfeltnorm(nf,n)^algdegree(B) + %9 = 16 + ? algnorm(,[0,sqrt(3),0,sqrt(2)]~) \\ Hamilton quaternions + %10 = 5.0000000000 + @eprog + Also accepts a square matrix with coefficients in \var{al}. + +Function: algpoleval +Class: basic +Section: algebras +C-Name: algpoleval +Prototype: DGGG +Help: algpoleval({al},T,b): T in K[X] evaluate T(b) in al (Hamilton quaternions + if omitted). +Doc: Given an element $b$ in \var{al} (Hamilton quaternions if omitted) and a + polynomial $T$ in $K[X]$, computes~$T(b)$ in~\var{al}. Here~$K = \Q$ or $\F_p$ + for a table algebra (output by \tet{algtableinit}) and $K$ is the center of + \var{al} for a central simple algebra (output by \tet{alginit}). + Also accepts as input a \typ{VEC}~$[b,mb]$ where~$mb$ is the left + multiplication table of~$b$. + + \bprog + ? nf = nfinit(y^2-5); + ? al = alginit(nf,[y,-1]); + ? b = [1..8]~; + ? pol = algcharpoly(al,b,,1); \\absolute characteristic polynomial + ? algpoleval(al,pol,b)==0 + %5 = 1 + ? mb = algtomatrix(al,b,1); + ? algpoleval(al,pol,[b,mb])==0 + %7 = 1 + ? pol = algcharpoly(al,b); \\reduced characteristic polynomial + ? algpoleval(al,pol,b) == 0 + %9 = 1 + ? algpoleval(,polcyclo(8),[1,0,0,1]~/sqrt(2)) \\ Hamilton quaternions + %10 = [0.E-38, 0, 0, 0.E-38]~ + @eprog + +Function: algpow +Class: basic +Section: algebras +C-Name: algpow +Prototype: DGGG +Help: algpow({al},x,n): element x^n in al (Hamilton quaternions if omitted). +Doc: Given an element $x$ in \var{al} (Hamilton quaternions if omitted) and an + integer $n$, computes the power $x^{n}$ in the algebra \var{al}. + \bprog + ? A = alginit(nfinit(y), [-1,-1]); + ? algpow(A,[1,1,0,0]~,7) + %2 = [8, -8, 0, 0]~ + ? algpow(,[1,2,3,sqrt(3)]~,-3) \\ Hamilton quaternions + % = [-0.0095664563, 0.0052920822, 0.0079381233, 0.0045830776]~ + @eprog + + Also accepts a square matrix with coefficients in \var{al}. + +Function: algprimesubalg +Class: basic +Section: algebras +C-Name: algprimesubalg +Prototype: G +Help: algprimesubalg(al): prime subalgebra of the positive characteristic, + semisimple algebra al. +Doc: \var{al} being the output of \tet{algtableinit} representing a semisimple + algebra of positive characteristic, returns a basis of the prime subalgebra + of~\var{al}. The prime subalgebra of~\var{al} is the subalgebra fixed by the + Frobenius automorphism of the center of \var{al}. It is abstractly isomorphic + to a product of copies of $\F_{p}$. + \bprog + ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; + ? A = algtableinit(mt,2); + ? algprimesubalg(A) + %3 = + [1 0] + + [0 1] + + [0 0] + @eprog + +Function: algquotient +Class: basic +Section: algebras +C-Name: alg_quotient +Prototype: GGD0,L, +Help: algquotient(al,I,{maps=0}): quotient of the algebra al by the two-sided + ideal I. +Doc: \var{al} being a table algebra output by \tet{algtableinit} and \var{I} + being a basis of a two-sided ideal of \var{al} represented by a matrix, + returns the quotient $\var{al}/\var{I}$. When $\var{maps}=1$, returns a + \typ{VEC} $[\var{al}/\var{I},\var{proj},\var{lift}]$ where \var{proj} and + \var{lift} are matrices respectively representing the projection map and a + section of it. + \bprog + ? mt = [matid(3), [0,0,0; 1,1,0; 0,0,0], [0,0,1; 0,0,0; 1,0,1]]; + ? A = algtableinit(mt,2); + ? AQ = algquotient(A,[0;1;0]); + ? algdim(AQ) + %4 = 2 + @eprog + +Function: algradical +Class: basic +Section: algebras +C-Name: algradical +Prototype: G +Help: algradical(al): Jacobson radical of the algebra al. +Doc: \var{al} being a table algebra output by \tet{algtableinit}, returns a + basis of the Jacobson radical of the algebra \var{al} over its prime field + ($\Q$ or $\F_{p}$). + + Here is an example with $A = \Q[x]/(x^{2})$, with the basis~$(1,x)$: + \bprog + ? mt = [matid(2),[0,0;1,0]]; + ? A = algtableinit(mt); + ? algradical(A) \\ = (x) + %3 = + [0] + + [1] + @eprog + + Another one with $2\times 2$ upper triangular matrices over $\Q$, with basis + $I_{2}$, $a = \kbd{[0,1;0,0]}$ and $b = \kbd{[0,0;0,1]}$, such that $a^{2} = + 0$, $ab = a$, $ba = 0$, $b^{2} = b$: + \bprog + ? mt = [matid(3),[0,0,0;1,0,1;0,0,0],[0,0,0;0,0,0;1,0,1]]; + ? A = algtableinit(mt); + ? algradical(A) \\ = (a) + %6 = + [0] + + [1] + + [0] + @eprog + +Function: algramifiedplaces +Class: basic +Section: algebras +C-Name: algramifiedplaces +Prototype: G +Help: algramifiedplaces(al): vector of the places of the center of al that + ramify in al. Each place is described as an integer between 1 and r1 or as a + prime ideal. +Doc: Given a central simple algebra \var{al} output by \tet{alginit}, returns a + \typ{VEC} containing the list of places of the center of \var{al} that are + ramified in \var{al}. Each place is described as an integer between~$1$ + and~$r_{1}$ or as a prime ideal. + + \bprog + ? nf = nfinit(y^2-5); + ? A = alginit(nf, [-1,y]); + ? algramifiedplaces(A) + %3 = [1, [2, [2, 0]~, 1, 2, 1]] + @eprog + +Function: algrandom +Class: basic +Section: algebras +C-Name: algrandom +Prototype: DGG +Help: algrandom({al},b): random element in al (Hamilton quaternions if omitted) + with coefficients in [-b,b]. +Doc: Given an algebra \var{al} and a nonnegative integer \var{b}, returns a + random element in \var{al} with coefficients in~$[-b,b]$. + + \bprog + ? al = alginit(nfinit(y),[-1,-1]); + ? algrandom(al,3) + % = [2, 0, 3, -1]~ + @eprog + + If~\var{al} is an algebra over $\R$ (Hamilton quaternions if omitted) and + \var{b} is a positive \typ{REAL}, returns a random element of~\var{al} with + coefficients in~$[-b,b]$. + + \bprog + ? algrandom(,1.) + % = [-0.1806334680, -0.2810504190, 0.5011479961, 0.9498643737]~ + @eprog + +Function: algrelmultable +Class: basic +Section: algebras +C-Name: algrelmultable +Prototype: mG +Help: algrelmultable(al): multiplication table of the central simple + algebra al over its center. +Doc: Given a central simple algebra \var{al} output by \tet{alginit} defined by a multiplication table over its center (a number field), returns this multiplication table. + \bprog + ? nf = nfinit(y^3-5); a = y; b = y^2; + ? {m_i = [0,a,0,0; + 1,0,0,0; + 0,0,0,a; + 0,0,1,0];} + ? {m_j = [0, 0,b, 0; + 0, 0,0,-b; + 1, 0,0, 0; + 0,-1,0, 0];} + ? {m_k = [0, 0,0,-a*b; + 0, 0,b, 0; + 0,-a,0, 0; + 1, 0,0, 0];} + ? mt = [matid(4), m_i, m_j, m_k]; + ? A = alginit(nf,mt,'x); + ? M = algrelmultable(A); + ? M[2] == m_i + %8 = 1 + ? M[3] == m_j + %9 = 1 + ? M[4] == m_k + %10 = 1 + @eprog + +Function: algsimpledec +Class: basic +Section: algebras +C-Name: algsimpledec +Prototype: GD0,L, +Help: algsimpledec(al,{maps=0}): [J,dec] where J is the Jacobson radical of al + and dec is the decomposition into simple algebras of the semisimple algebra + al/J. +Doc: \var{al} being the output of \tet{algtableinit}, returns a \typ{VEC} + $[J,[\var{al}_{1},\dots,\var{al}_{n}]]$ where $J$ is a basis of the + Jacobson radical of \var{al} and~$\var{al}/J$ is isomorphic to the direct + product of the simple algebras~$\var{al}_{i}$. When $\var{maps}=1$, + each~$\var{al}_{i}$ is replaced with a \typ{VEC} + $[\var{al}_{i},\var{proj}_{i},\var{lift}_{i}]$ where $\var{proj}_{i}$ + and~$\var{lift}_{i}$ + are matrices respectively representing the projection map~$\var{al} \to + \var{al}_{i}$ and a section of it. Modulo~$J$, the images of the + $\var{lift}_{i}$ + form a direct sum in~$\var{al}/J$, so that the images of~$1\in\var{al}_{i}$ + under~$\var{lift}_{i}$ are central primitive idempotents of~$\var{al}/J$. The + factors are sorted by increasing dimension, then increasing dimension of the + center. This ensures that the ordering of the isomorphism classes of the + factors is deterministic over finite fields, but not necessarily over~$\Q$. + +Function: algsplit +Class: basic +Section: algebras +C-Name: algsplit +Prototype: GDn +Help: algsplit(al,{v='x}): computes an isomorphism between al and M_d(F_q). +Doc: If \var{al} is a table algebra over~$\F_{p}$ output by \tet{algtableinit} + that represents a simple algebra, computes an isomorphism between \var{al} and + a matrix algebra~$M_{d}(\F_{p^{n}})$ where~$N = nd^{2}$ is the dimension + of~\var{al}. Returns a \typ{VEC}~$[map,mapi]$, where: + + \item \var{map} is a \typ{VEC} of~$N$ matrices of size~$d\times d$ with + \typ{FFELT} coefficients using the variable~\var{v}, representing the image of + the basis of~\var{al} under the isomorphism. + + \item \var{mapi} is an~$N\times N$ matrix with \typ{INT} coefficients, + representing the image in \var{al} by the inverse isomorphism of the + basis~$(b_{i})$ of~$M_{d}(\F_{p}[\alpha])$ (where~$\alpha$ has degree~$n$ + over~$\F_{p}$) defined as follows: + let~$E_{i,j}$ be the matrix having all coefficients~$0$ except the~$(i,j)$-th + coefficient equal to~$1$, and define + $$b_{i_{3}+n(i_{2}+di_{1})+1} = E_{i_{1}+1,i_{2}+1} \alpha^{i_{3}},$$ + where~$0\le i_{1},i_{2} 0$, a new stack of at least $s$ bytes is allocated. We may allocate + more than $s$ bytes if $s$ is way too small, or for alignment reasons: the + current formula is $\max(16*\ceil{s/16}, 500032)$ bytes. + + If $s=0$, the size of the new stack is twice the size of the old one. + + This command is much more useful if \tet{parisizemax} is nonzero, and we + describe this case first. With \kbd{parisizemax} enabled, there are three + sizes of interest: + + \item a virtual stack size, \tet{parisizemax}, which is an absolute upper + limit for the stack size; this is set by \kbd{default(parisizemax, ...)}. + + \item the desired typical stack size, \tet{parisize}, that will grow as + needed, up to \tet{parisizemax}; this is set by \kbd{default(parisize, ...)}. + + \item the current stack size, which is less that \kbd{parisizemax}, + typically equal to \kbd{parisize} but possibly larger and increasing + dynamically as needed; \kbd{allocatemem} allows to change that one + explicitly. + + The \kbd{allocatemem} command forces stack + usage to increase temporarily (up to \kbd{parisizemax} of course); for + instance if you notice using \kbd{\bs gm2} that we seem to collect garbage a + lot, e.g. + \bprog + ? \gm2 + debugmem = 2 + ? default(parisize,"32M") + *** Warning: new stack size = 32000000 (30.518 Mbytes). + ? bnfinit('x^2+10^30-1) + *** bnfinit: collecting garbage in hnffinal, i = 1. + *** bnfinit: collecting garbage in hnffinal, i = 2. + *** bnfinit: collecting garbage in hnffinal, i = 3. + @eprog\noindent and so on for hundred of lines. Then, provided the + \tet{breakloop} default is set, you can interrupt the computation, type + \kbd{allocatemem(100*10\pow6)} at the break loop prompt, then let the + computation go on by typing \kbd{}. Back at the \kbd{gp} prompt, + the desired stack size of \kbd{parisize} is restored. Note that changing either + \kbd{parisize} or \kbd{parisizemax} at the break loop prompt would interrupt + the computation, contrary to the above. + + In most cases, \kbd{parisize} will increase automatically (up to + \kbd{parisizemax}) and there is no need to perform the above maneuvers. + But that the garbage collector is sufficiently efficient that + a given computation can still run without increasing the stack size, + albeit very slowly due to the frequent garbage collections. + + \misctitle{Deprecated: when \kbd{parisizemax} is unset} + This is currently still the default behavior in order not to break backward + compatibility. The rest of this section documents the + behavior of \kbd{allocatemem} in that (deprecated) situation: it becomes a + synonym for \kbd{default(parisize,...)}. In that case, there is no + notion of a virtual stack, and the stack size is always equal to + \kbd{parisize}. If more memory is needed, the PARI stack overflows, aborting + the computation. + + Thus, increasing \kbd{parisize} via \kbd{allocatemem} or + \kbd{default(parisize,...)} before a big computation is important. + Unfortunately, either must be typed at the \kbd{gp} prompt in + interactive usage, or left by itself at the start of batch files. + They cannot be used meaningfully in loop-like constructs, or as part of a + larger expression sequence, e.g + \bprog + allocatemem(); x = 1; \\@com This will not set \kbd{x}! + @eprog\noindent + In fact, all loops are immediately exited, user functions terminated, and + the rest of the sequence following \kbd{allocatemem()} is silently + discarded, as well as all pending sequences of instructions. We just go on + reading the next instruction sequence from the file we are in (or from the + user). In particular, we have the following possibly unexpected behavior: in + \bprog + read("file.gp"); x = 1 + @eprog\noindent were \kbd{file.gp} contains an \kbd{allocatemem} statement, + the \kbd{x = 1} is never executed, since all pending instructions in the + current sequence are discarded. + + The reason for these unfortunate side-effects is that, with + \kbd{parisizemax} disabled, increasing the stack size physically + moves the stack, so temporary objects created during the current expression + evaluation are not correct anymore. (In particular byte-compiled expressions, + which are allocated on the stack.) To avoid accessing obsolete pointers to + the old stack, this routine ends by a \kbd{longjmp}. + +Function: apply +Class: basic +Section: programming/specific +C-Name: apply0 +Prototype: GG +Help: apply(f,A): apply function f to each entry in A. +Wrapper: (G) +Description: + (closure,gen):gen genapply(${1 cookie}, ${1 wrapper}, $2) +Doc: Apply the \typ{CLOSURE} \kbd{f} to the entries of \kbd{A}. + + \item If \kbd{A} is a scalar, return \kbd{f(A)}. + + \item If \kbd{A} is a polynomial or power series $\sum a_{i} x^{i}$ ($+ + O(x^{N})$), apply \kbd{f} on all coefficients and return $\sum f(a_{i}) + x^{i}$ ($+ O(x^{N})$). + + \item If \kbd{A} is a vector or list $[a_{1},\dots,a_{n}]$, return the vector + or list $[f(a_{1}),\dots, f(a_{n})]$. If \kbd{A} is a matrix, return the matrix + whose entries are the $f(\kbd{A[i,j]})$. + + \bprog + ? apply(x->x^2, [1,2,3,4]) + %1 = [1, 4, 9, 16] + ? apply(x->x^2, [1,2;3,4]) + %2 = + [1 4] + + [9 16] + ? apply(x->x^2, 4*x^2 + 3*x+ 2) + %3 = 16*x^2 + 9*x + 4 + ? apply(sign, 2 - 3* x + 4*x^2 + O(x^3)) + %4 = 1 - x + x^2 + O(x^3) + @eprog\noindent Note that many functions already act componentwise on + vectors or matrices, but they almost never act on lists; in this case, + \kbd{apply} is a good solution: + \bprog + ? L = List([Mod(1,3), Mod(2,4)]); + ? lift(L) + *** at top-level: lift(L) + *** ^------- + *** lift: incorrect type in lift. + ? apply(lift, L); + %2 = List([1, 2]) + @eprog + \misctitle{Remark} For $v$ a \typ{VEC}, \typ{COL}, \typ{VECSMALL}, + \typ{LIST} or \typ{MAT}, the alternative set-notations + \bprog + [g(x) | x <- v, f(x)] + [x | x <- v, f(x)] + [g(x) | x <- v] + @eprog\noindent + are available as shortcuts for + \bprog + apply(g, select(f, Vec(v))) + select(f, Vec(v)) + apply(g, Vec(v)) + @eprog\noindent respectively: + \bprog + ? L = List([Mod(1,3), Mod(2,4)]); + ? [ lift(x) | x<-L ] + %2 = [1, 2] + @eprog + + \synt{genapply}{void *E, GEN (*fun)(void*,GEN), GEN a}. + +Function: arg +Class: basic +Section: transcendental +C-Name: garg +Prototype: Gp +Help: arg(x): argument of x, such that -pi1$ then $\text{asin}(x)$ is complex. The branch cut is in two pieces: + $]-\infty,-1]$, continuous with quadrant II, and $[1,+\infty[$ continuous + with quadrant IV. The function satisfies $i \text{asin}(x) = + \text{asinh}(ix)$. + +Function: asinh +Class: basic +Section: transcendental +C-Name: gasinh +Prototype: Gp +Help: asinh(x): inverse hyperbolic sine of x. +Doc: principal branch of $\sinh^{-1}(x) = \log(x + \sqrt{1+x^{2}})$. In + particular $\Im(\text{asinh}(x))\in [-\pi/2,\pi/2]$. + The branch cut is in two pieces: $]-i \infty ,-i]$, continuous with quadrant + III and $[+i,+i \infty[$, continuous with quadrant I. + +Function: asympnum +Class: basic +Section: sums +C-Name: asympnum0 +Prototype: GDGp +Help: asympnum(expr,{alpha = 1}): asymptotic expansion of expr + assuming it has rational coefficients with reasonable height; alpha is + as in limitnum. +Doc: Asymptotic expansion of \var{expr}, corresponding to a sequence $u(n)$, + assuming it has the shape + $$u(n) \approx \sum_{i \geq 0} a_{i} n^{-i\alpha}$$ + with rational coefficients $a_{i}$ with reasonable height; the algorithm + is heuristic and performs repeated calls to limitnum, with + \kbd{alpha} as in \kbd{limitnum}. As in \kbd{limitnum}, $u(n)$ may be + given either by a closure $n\mapsto u(n)$ or as a closure $N\mapsto + [u(1),\dots,u(N)]$, the latter being often more efficient. + \bprog + ? f(n) = n! / (n^n*exp(-n)*sqrt(n)); + ? asympnum(f) + %2 = [] \\ failure ! + ? localprec(57); l = limitnum(f) + %3 = 2.5066282746310005024157652848110452530 + ? asympnum(n->f(n)/l) \\ normalize + %4 = [1, 1/12, 1/288, -139/51840, -571/2488320, 163879/209018880, + 5246819/75246796800] + @eprog\noindent and we indeed get a few terms of Stirling's expansion. Note + that it definitely helps to normalize with a limit computed to higher + accuracy (as a rule of thumb, multiply the bit accuracy by $1.612$): + \bprog + ? l = limitnum(f) + ? asympnum(n->f(n) / l) \\ failure again !!! + %6 = [] + @eprog\noindent We treat again the example of the Motzkin numbers $M_{n}$ given + in \kbd{limitnum}: + \bprog + \\ [M_k, M_{k*2}, ..., M_{k*N}] / (3^n / n^(3/2)) + ? vM(N, k = 1) = + { my(q = k*N, V); + if (q == 1, return ([1/3])); + V = vector(q); V[1] = V[2] = 1; + for(n = 2, q - 1, + V[n+1] = ((2*n + 1)*V[n] + 3*(n - 1)*V[n-1]) / (n + 2)); + f = (n -> 3^n / n^(3/2)); + return (vector(N, n, V[n*k] / f(n*k))); + } + ? localprec(100); l = limitnum(n->vM(n,10)); \\ 3/sqrt(12*Pi) + ? \p38 + ? asympnum(n->vM(n,10)/l) + %2 = [1, -3/32, 101/10240, -1617/1638400, 505659/5242880000, ...] + @eprog + + If \kbd{alpha} is not a rational number, loss of accuracy is + expected, so it should be precomputed to double accuracy, say: + \bprog + ? \p38 + ? asympnum(n->log(1+1/n^Pi),Pi) + %1 = [0, 1, -1/2, 1/3, -1/4, 1/5] + ? localprec(76); a = Pi; + ? asympnum(n->log(1+1/n^Pi), a) \\ more terms + %3 = [0, 1, -1/2, 1/3, -1/4, 1/5, -1/6, 1/7, -1/8, 1/9, -1/10, 1/11, -1/12] + ? asympnum(n->log(1+1/sqrt(n)),1/2) \\ many more terms + %4 = 49 + @eprog The expression is evaluated for $n = 1, 2, \dots, N$ + for an $N = O(B)$ if the current bit accuracy is $B$. If it is not defined + for one of these values, translate or rescale accordingly: + \bprog + ? asympnum(n->log(1-1/n)) \\ can't evaluate at n = 1 ! + *** at top-level: asympnum(n->log(1-1/n)) + *** ^----------------------- + *** in function asympnum: log(1-1/n) + *** ^---------- + *** log: domain error in log: argument = 0 + ? asympnum(n->-log(1-1/(2*n))) + %5 = [0, 1/2, 1/8, 1/24, ...] + ? asympnum(n->-log(1-1/(n+1))) + %6 = [0, 1, -1/2, 1/3, -1/4, ...] + @eprog\noindent + + \synt{asympnum}{void *E, GEN (*u)(void *,GEN,long), GEN alpha, long prec}, where \kbd{u(E, n, prec)} must return either $u(n)$ or $[u(1),\dots,u(n)]$ + in precision \kbd{prec}. Also available is + \fun{GEN}{asympnum0}{GEN u, GEN alpha, long prec}, where $u$ is a closure + as above or a vector of sufficient length. + +Function: asympnumraw +Class: basic +Section: sums +C-Name: asympnumraw0 +Prototype: GLDGp +Help: asympnumraw(expr,N,{alpha = 1}): N+1 first terms of asymptotic expansion + of expr as floating point numbers; alpha is as in limitnum. +Doc: Return the $N+1$ first terms of asymptotic expansion of \var{expr}, + corresponding to a sequence $u(n)$, as floating point numbers. Assume + that the expansion has the shape + $$u(n) \approx \sum_{i \geq 0} a_{i} n^{-i\alpha}$$ + and return approximation of $[a_{0}, a_{1},\dots, a_{N}]$. + The algorithm is heuristic and performs repeated calls to limitnum, with + \kbd{alpha} as in \kbd{limitnum}. As in \kbd{limitnum}, $u(n)$ may be + given either by a closure $n\mapsto u(n)$ or as a closure $N\mapsto + [u(1),\dots,u(N)]$, the latter being often more efficient. This function + is related to, but more flexible than, \kbd{asympnum}, which requires + rational asymptotic expansions. + \bprog + ? f(n) = n! / (n^n*exp(-n)*sqrt(n)); + ? asympnum(f) + %2 = [] \\ failure ! + ? v = asympnumraw(f, 10); + ? v[1] - sqrt(2*Pi) + %4 = 0.E-37 + ? bestappr(v / v[1], 2^60) + %5 = [1, 1/12, 1/288, -139/51840, -571/2488320, 163879/209018880,...] + @eprog\noindent and we indeed get a few terms of Stirling's expansion (the + first 9 terms are correct). + If $u(n)$ has an asymptotic expansion in $n^{-\alpha}$ with $\alpha$ not an + integer, the default $alpha=1$ is inaccurate: + \bprog + ? f(n) = (1+1/n^(7/2))^(n^(7/2)); + ? v1 = asympnumraw(f,10); + ? v1[1] - exp(1) + %8 = 4.62... E-12 + ? v2 = asympnumraw(f,10,7/2); + ? v2[1] - exp(1) + %7 0.E-37 + @eprog\noindent + As in \kbd{asympnum}, if \kbd{alpha} is not a rational number, + loss of accuracy is expected, so it should be precomputed to double + accuracy, say. + + \synt{asympnumraw}{void *E, GEN (*u)(void *,GEN,long), long N, GEN alpha, long prec}, where \kbd{u(E, n, prec)} must return either $u(n)$ or + $[u(1),\dots,u(n)]$ in precision \kbd{prec}. + Also available is + \fun{GEN}{asympnumraw0}{GEN u, GEN alpha, long prec} where $u$ is either + a closure as above or a vector of sufficient length. + +Function: atan +Class: basic +Section: transcendental +C-Name: gatan +Prototype: Gp +Help: atan(x): arc tangent of x. +Doc: principal branch of $\text{tan}^{-1}(x) = \log ((1+ix)/(1-ix)) / + 2i$. In particular the real part of $\text{atan}(x)$ belongs to + $]-\pi/2,\pi/2[$. + The branch cut is in two pieces: + $]-i\infty,-i[$, continuous with quadrant IV, and $]i,+i \infty[$ continuous + with quadrant II. The function satisfies $\text{atan}(x) = + -i\text{atanh}(ix)$ for all $x\neq \pm i$. + +Function: atanh +Class: basic +Section: transcendental +C-Name: gatanh +Prototype: Gp +Help: atanh(x): inverse hyperbolic tangent of x. +Doc: principal branch of $\text{tanh}^{-1}(x) = \log ((1+x)/(1-x)) / 2$. In + particular the imaginary part of $\text{atanh}(x)$ belongs to + $[-\pi/2,\pi/2]$; if $x\in \R$ and $|x|>1$ then $\text{atanh}(x)$ is complex. + +Function: bernfrac +Class: basic +Section: combinatorics +C-Name: bernfrac +Prototype: L +Help: bernfrac(n): Bernoulli number B_n, as a rational number. +Doc: Bernoulli number\sidx{Bernoulli numbers} $B_{n}$, + where $B_{0}=1$, $B_{1}=-1/2$, $B_{2}=1/6$,\dots, expressed as a rational + number. + The argument $n$ should be a nonnegative integer. The function \tet{bernvec} + creates a cache of successive Bernoulli numbers which greatly speeds up + later calls to \kbd{bernfrac}: + \bprog + ? bernfrac(20000); + time = 107 ms. + ? bernvec(10000); \\ cache B_0, B_2, ..., B_20000 + time = 35,957 ms. + ? bernfrac(20000); \\ now instantaneous + ? + @eprog + +Function: bernpol +Class: basic +Section: combinatorics +C-Name: bernpol_eval +Prototype: LDG +Help: bernpol(n,{a='x}): Bernoulli polynomial B_n, evaluated at a +Doc: \idx{Bernoulli polynomial} $B_{n}$ evaluated at $a$ (\kbd{'x} by default), + defined by + $$ + \sum_{n=0}^{\infty}B_{n}(x)\dfrac{T^{n}}{n!} = \dfrac{Te^{xT}}{e^{T}-1}. + $$ + \bprog + ? bernpol(1) + %1 = x - 1/2 + ? bernpol(3) + %2 = x^3 - 3/2*x^2 + 1/2*x + ? bernpol(3, 2) + %3 = 3 + @eprog\noindent Note that evaluation at $a$ is only provided for convenience + and uniformity of interface: contrary to, e.g., \kbd{polcyclo}, computing + the evaluation is no faster than + \bprog + B = bernpol(k); subst(B, 'x, a) + @eprog\noindent and the latter allows to reuse $B$ to evaluate $B_{k}$ + at different values. +Variant: The variant \fun{GEN}{bernpol}{long k, long v} returns + the $k$-the Bernoulli polynomial in variable $v$. + +Function: bernreal +Class: basic +Section: combinatorics +C-Name: bernreal +Prototype: Lp +Help: bernreal(n): Bernoulli number B_n, as a real number with the current + precision. +Doc: Bernoulli number\sidx{Bernoulli numbers} + $B_{n}$, as \kbd{bernfrac}, but $B_{n}$ is returned as a real number + (with the current precision). The argument $n$ should be a nonnegative + integer. The function slows down as the precision increases: + \bprog + ? \p1000 + ? bernreal(200000); + time = 5 ms. + ? \p10000 + ? bernreal(200000); + time = 18 ms. + ? \p100000 + ? bernreal(200000); + time = 84 ms. + @eprog + +Function: bernvec +Class: basic +Section: combinatorics +C-Name: bernvec +Prototype: L +Help: bernvec(n): returns a vector containing, as rational numbers, + the Bernoulli numbers B_0, B_2, ..., B_{2n}. +Doc: returns a vector containing, as rational numbers, + the \idx{Bernoulli numbers} $B_{0}$, $B_{2}$,\dots, $B_{2n}$: + \bprog + ? bernvec(5) \\ B_0, B_2..., B_10 + %1 = [1, 1/6, -1/30, 1/42, -1/30, 5/66] + ? bernfrac(10) + %2 = 5/66 + @eprog\noindent This routine uses a lot of memory but is much faster than + repeated calls to \kbd{bernfrac}: + \bprog + ? forstep(n = 2, 10000, 2, bernfrac(n)) + time = 18,245 ms. + ? bernvec(5000); + time = 1,338 ms. + @eprog\noindent The computed Bernoulli numbers are stored in an incremental + cache which makes later calls to \kbd{bernfrac} and \kbd{bernreal} + instantaneous in the cache range: re-running the same previous \kbd{bernfrac}s + after the \kbd{bernvec} call gives: + \bprog + ? forstep(n = 2, 10000, 2, bernfrac(n)) + time = 1 ms. + @eprog\noindent The time and space complexity of this function are + $\tilde{O}(n^{2})$; in the feasible range $n \leq 10^{5}$ (requires about two + hours), the practical time complexity is closer to $\tilde{O}(n^{\log_{2} 6})$. + +Function: besselh1 +Class: basic +Section: transcendental +C-Name: hbessel1 +Prototype: GGp +Help: besselh1(nu,x): H^1-bessel function of index nu and argument x. +Doc: $H^{1}$-Bessel function of index \var{nu} and argument $x$. + +Function: besselh2 +Class: basic +Section: transcendental +C-Name: hbessel2 +Prototype: GGp +Help: besselh2(nu,x): H^2-bessel function of index nu and argument x. +Doc: $H^{2}$-Bessel function of index \var{nu} and argument $x$. + +Function: besseli +Class: basic +Section: transcendental +C-Name: ibessel +Prototype: GGp +Help: besseli(nu,x): I-bessel function of index nu and argument x. +Doc: $I$-Bessel function of index \var{nu} and + argument $x$. If $x$ converts to a power series, the initial factor + $(x/2)^{\nu}/\Gamma(\nu+1)$ is omitted (since it cannot be represented in PARI + when $\nu$ is not integral). + +Function: besselj +Class: basic +Section: transcendental +C-Name: jbessel +Prototype: GGp +Help: besselj(nu,x): J-bessel function of index nu and argument x. +Doc: $J$-Bessel function of index \var{nu} and + argument $x$. If $x$ converts to a power series, the initial factor + $(x/2)^{\nu}/\Gamma(\nu+1)$ is omitted (since it cannot be represented in + PARI when $\nu$ is not integral). + +Function: besseljh +Class: basic +Section: transcendental +C-Name: jbesselh +Prototype: GGp +Help: besseljh(n,x): J-bessel function of index n+1/2 and argument x, where + n is a nonnegative integer. +Doc: $J$-Bessel function of half integral index. + More precisely, $\kbd{besseljh}(n,x)$ computes $J_{n+1/2}(x)$ where $n$ + must be of type integer, and $x$ is any element of $\C$. In the + present version \vers, this function is not very accurate when $x$ is small. + +Function: besseljzero +Class: basic +Section: transcendental +C-Name: besseljzero +Prototype: GD1,L,b +Help: besseljzero(nu,{k=1}): k-th zero of the J-bessel function of index nu. Works for real and complex ordrers but the result is guaranteed only if nu is nonnegative. +Doc: $k$-th zero of the $J$-Bessel function of index \var{nu}, close + to $\pi(\nu/2 + k - 1/4)$, usually noted $j_{\nu,k}$. + \bprog + ? besseljzero(0) \\ @com{first zero of $J_{0}$} + %1 = 2.4048255576957727686216318793264546431 + ? besselj(0, %) + %2 = 7.1951595399463653939930598011247182898 E-41 + ? besseljzero(0, 2) \\ @com{second zero} + %3 = 5.5200781102863106495966041128130274252 + ? besseljzero(I) \\ @com{also works for complex orders, here $J_{i}$} + %4 = 2.5377... + 1.4753...*I + @eprog\noindent The function uses a Newton iteration due to Temme. + If $\nu$ is real and nonnegative, the result is guaranteed and the function really + returns the $k$-th positive zero of $J_{\nu}$. For general $\nu$, the result + is not well defined, given by the Newton iteration with $\pi(\nu/2 + k - 1/4)$ + as a starting value. (N.B. Using this method for large real $\nu$ would give + completely different results than the $j_{\nu,k}$ unless $k$ is large enough.) + +Function: besselk +Class: basic +Section: transcendental +C-Name: kbessel +Prototype: GGp +Help: besselk(nu,x): K-bessel function of index nu and argument x. +Doc: $K$-Bessel function of index \var{nu} and argument $x$. + +Function: besseln +Class: basic +Section: transcendental +C-Name: ybessel +Prototype: GGp +Obsolete: 2018-12-10 +Help: besseln(nu,x): deprecated alias for bessely. +Doc: deprecated alias for \kbd{bessely}. + +Function: bessely +Class: basic +Section: transcendental +C-Name: ybessel +Prototype: GGp +Help: bessely(nu,x): Y-bessel function of index nu and argument x. +Doc: $Y$-Bessel function of index \var{nu} and argument $x$. + +Function: besselyzero +Class: basic +Section: transcendental +C-Name: besselyzero +Prototype: GD1,L,b +Help: besselyzero(nu,{k=1}): k-th zero of the Y-bessel function of index nu. Works for real and complex ordrers but the result is guaranteed only if nu is nonnegative. +Doc: $k$-th zero of the $Y$-Bessel function of index \var{nu}, close + to $\pi(\nu/2 + k - 3/4)$, usually noted $y_{\nu,k}$. + \bprog + ? besselyzero(0) \\ @com{first zero of $Y_{0}$} + %1 = 0.89357696627916752158488710205833824123 + ? bessely(0, %) + %2 = 1.8708573650996561952 E-39 + ? besselyzero(0, 2) \\ @com{second zero} + %3 = 3.9576784193148578683756771869174012814 + ? besselyzero(I) \\ @com{also works for complex orders, here $Y_{i}$} + %4 = 1.03930... + 1.3266...*I + @eprog\noindent The function uses a Newton iteration due to Temme. + If $\nu$ is real and nonnegative, the result is guaranteed and the function really + returns the $k$-th positive zero of $Y_{\nu}$. For general $\nu$, the result + is not well defined, given by Newton iteration with $\pi(\nu/2 + k - 3/4)$ + as a starting value. (N.B. Using this method for large real $\nu$ would give + completely different results than the $y_{\nu,k}$ unless $k$ is large enough.) + +Function: bestappr +Class: basic +Section: number_theoretical +C-Name: bestappr +Prototype: GDG +Help: bestappr(x,{B}): return a rational approximation to x, whose + denominator is limited by B, if present. This function applies to reals, + intmods, p-adics, and rationals of course. Otherwise it applies recursively + to all components. +Doc: using variants of the extended Euclidean algorithm, returns a rational + approximation $a/b$ to $x$, whose denominator is limited + by $B$, if present. If $B$ is omitted, returns the best approximation + affordable given the input accuracy; if you are looking for true rational + numbers, presumably approximated to sufficient accuracy, you should first + try that option. Otherwise, $B$ must be a positive real scalar (impose + $0 < b \leq B$). + + \item If $x$ is a \typ{REAL} or a \typ{FRAC}, this function uses continued + fractions. + \bprog + ? bestappr(Pi, 100) + %1 = 22/7 + ? bestappr(0.1428571428571428571428571429) + %2 = 1/7 + ? bestappr([Pi, sqrt(2) + 'x], 10^3) + %3 = [355/113, x + 1393/985] + @eprog + By definition, $a/b$ is the best rational approximation to $x$ if + $|b x - a| < |v x - u|$ for all integers $(u,v)$ with $0 < v \leq B$. + (Which implies that $n/d$ is a convergent of the continued fraction of $x$.) + + \item If $x$ is a \typ{INTMOD} modulo $N$ or a \typ{PADIC} of precision $N = + p^{k}$, this function performs rational modular reconstruction modulo $N$. The + routine then returns the unique rational number $a/b$ in coprime integers + $|a| < N/2B$ and $b\leq B$ which is congruent to $x$ modulo $N$. Omitting + $B$ amounts to choosing it of the order of $\sqrt{N/2}$. If rational + reconstruction is not possible (no suitable $a/b$ exists), returns $[]$. + \bprog + ? bestappr(Mod(18526731858, 11^10)) + %1 = 1/7 + ? bestappr(Mod(18526731858, 11^20)) + %2 = [] + ? bestappr(3 + 5 + 3*5^2 + 5^3 + 3*5^4 + 5^5 + 3*5^6 + O(5^7)) + %2 = -1/3 + @eprog\noindent In most concrete uses, $B$ is a prime power and we performed + Hensel lifting to obtain $x$. + + The function applies recursively to components of complex objects + (polynomials, vectors, \dots). If rational reconstruction fails for even a + single entry, returns $[]$. + +Function: bestapprPade +Class: basic +Section: number_theoretical +C-Name: bestapprPade0 +Prototype: GD-1,L,D-1,L, +Help: bestapprPade(x,{B},{Q}): returns a rational function approximation to x. + This function applies to series, polmods, and rational functions of course. + Otherwise it applies recursively to all components. +Doc: using variants of the extended Euclidean algorithm (Pad\'{e} + approximants), returns a rational + function approximation $a/b$ to $x$, whose denominator is limited + by $B$, if present. If $B$ is omitted, return the best approximation + affordable given the input accuracy; if you are looking for true rational + functions, presumably approximated to sufficient accuracy, you should first + try that option. Otherwise, $B$ must be a nonnegative real + (impose $0 \leq \text{degree}(b) \leq B$). + + \item If $x$ is a \typ{POLMOD} modulo $N$ this function performs rational + modular reconstruction modulo $N$. The routine then returns the unique + rational function $a/b$ in coprime polynomials, with $\text{degree}(b)\leq B$ + and $\text{degree}(a)$ minimal, which is congruent to $x$ modulo $N$. + Omitting $B$ amounts to choosing it equal to the floor of + $\text{degree}(N) / 2$. If rational reconstruction is not possible (no + suitable $a/b$ exists), returns $[]$. + \bprog + ? T = Mod(x^3 + x^2 + x + 3, x^4 - 2); + ? bestapprPade(T) + %2 = (2*x - 1)/(x - 1) + ? U = Mod(1 + x + x^2 + x^3 + x^5, x^9); + ? bestapprPade(U) \\ internally chooses B = 4 + %3 = [] + ? bestapprPade(U, 5) \\ with B = 5, a solution exists + %4 = (2*x^4 + x^3 - x - 1)/(-x^5 + x^3 + x^2 - 1) + @eprog + + \item If $x$ is a \typ{SER}, we implicitly + convert the input to a \typ{POLMOD} modulo $N = t^{k}$ where $k$ is the + series absolute precision. + \bprog + ? T = 1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + O(t^7); \\ mod t^7 + ? bestapprPade(T) + %1 = 1/(-t + 1) + @eprog + \item If $x$ is a \typ{SER} and both $B$ and $Q$ are nonnegative, + returns a rational function approximation $a/b$ + to $x$, with $a$ of degree at most $B$ and $b$ of degree at most $Q$, with + $x-a/b=O(t^{B+Q+1+v})$ if $t$ is the variable, where $v$ is the valuation + of $x$, the empty vector if not possible. + + \item If $x$ is a \typ{RFRAC}, we implicitly convert the input to a + \typ{POLMOD} modulo $N = t^{k}$ where $k = 2B + 1$. If $B$ was omitted, + we return $x$: + \bprog + ? T = (4*t^2 + 2*t + 3)/(t+1)^10; + ? bestapprPade(T,1) + %2 = [] \\ impossible + ? bestapprPade(T,2) + %3 = 27/(337*t^2 + 84*t + 9) + ? bestapprPade(T,3) + %4 = (4253*t - 3345)/(-39007*t^3 - 28519*t^2 - 8989*t - 1115) + @eprog\noindent + The function applies recursively to components of complex objects + (polynomials, vectors, \dots). If rational reconstruction fails for even a + single entry, return $[]$. +Variant: + \fun{GEN}{bestapprPade}{GEN x, long B} as \kbd{bestapprPade0} when Q is ommited. + +Function: bestapprnf +Class: basic +Section: linear_algebra +C-Name: bestapprnf +Prototype: GGDGp +Help: bestapprnf(V,T,{rootT}): T being an integral polynomial + and V being a scalar, vector, or matrix, return a reasonable + approximation of V with polmods modulo T. The rootT argument, + if present, must be an element of polroots(T), i.e. a root of T fixing a + complex embedding of Q[x]/(T). +Doc: $T$ being an integral polynomial and $V$ being a scalar, vector, or + matrix with complex coefficients, return a reasonable approximation of $V$ + with polmods modulo $T$. $T$ can also be any number field structure, in which + case the minimal polynomial attached to the structure (\kbd{$T$}.pol) is + used. The \var{rootT} argument, if present, must be an element of + \kbd{polroots($T$)} (or \kbd{$T$}.pol), i.e.~a complex root of $T$ fixing an embedding of + $\Q[x]/(T)$ into $\C$. + \bprog + ? bestapprnf(sqrt(5), polcyclo(5)) + %1 = Mod(-2*x^3 - 2*x^2 - 1, x^4 + x^3 + x^2 + x + 1) + ? bestapprnf(sqrt(5), polcyclo(5), exp(4*I*Pi/5)) + %2 = Mod(2*x^3 + 2*x^2 + 1, x^4 + x^3 + x^2 + x + 1) + @eprog\noindent When the output has huge rational coefficients, try to + increase the working \kbd{realbitprecision}: if the answer does not + stabilize, consider that the reconstruction failed. + Beware that if $T$ is not Galois over $\Q$, some embeddings + may not allow to reconstruct $V$: + \bprog + ? T = x^3-2; vT = polroots(T); z = 3*2^(1/3)+1; + ? bestapprnf(z, T, vT[1]) + %2 = Mod(3*x + 1, x^3 - 2) + ? bestapprnf(z, T, vT[2]) + %3 = 4213714286230872/186454048314072 \\ close to 3*2^(1/3) + 1 + @eprog + +Function: bezout +Class: basic +Section: number_theoretical +C-Name: gcdext0 +Prototype: GG +Obsolete: 2013-04-03 +Help: bezout(x,y): deprecated alias for gcdext. +Doc: deprecated alias for \kbd{gcdext} + +Function: bezoutres +Class: basic +Section: polynomials +C-Name: polresultantext0 +Prototype: GGDn +Obsolete: 2015-01-13 +Help: bezoutres(A,B,{v}): deprecated alias for polresultantext. +Doc: deprecated alias for \kbd{polresultantext} + +Function: bigomega +Class: basic +Section: number_theoretical +C-Name: bigomega +Prototype: lG +Help: bigomega(x): number of prime divisors of x, counted with multiplicity. +Doc: number of prime divisors of the integer $|x|$ counted with + multiplicity: + \bprog + ? factor(392) + %1 = + [2 3] + + [7 2] + + ? bigomega(392) + %2 = 5; \\ = 3+2 + ? omega(392) + %3 = 2; \\ without multiplicity + @eprog + +Function: binary +Class: basic +Section: conversions +C-Name: binaire +Prototype: G +Help: binary(x): gives the vector formed by the binary digits of x (x + integer). +Doc: outputs the vector of the binary digits of $|x|$. Here $x$ can be an + integer, a real number (in which case the result has two components, one for + the integer part, one for the fractional part) or a vector/matrix. + \bprog + ? binary(10) + %1 = [1, 0, 1, 0] + + ? binary(3.14) + %2 = [[1, 1], [0, 0, 1, 0, 0, 0, [...]] + + ? binary([1,2]) + %3 = [[1], [1, 0]] + @eprog\noindent For integer $x\ge1$, the number of bits is + $\kbd{logint}(x,2) + 1$. By convention, $0$ has no digits: + \bprog + ? binary(0) + %4 = [] + @eprog + +Function: binomial +Class: basic +Section: combinatorics +C-Name: binomial0 +Prototype: GDG +Help: binomial(n,{k}): binomial coefficient n*(n-1)...*(n-k+1)/k! defined for + k in Z and any n. If k is omitted and n a nonnegative integer, return the + vector [binomial(n,0),...,binomial(n,n)]. +Doc: \idx{binomial coefficient} $\binom{n}{k}$. + Here $k$ must be an integer, but $n$ can be any PARI object. For nonnegative + $k$, $\binom{n}{k} = (n)_{k} / k!$ is polynomial in $n$, where $(n)_{k} = + n(n-1)\dots(n-k+1)$ is the Pochhammer symbol used by combinatorists (which is + different from the one used by analysts). + \bprog + ? binomial(4,2) + %1 = 6 + ? n = 4; vector(n+1, k, binomial(n,k-1)) + %2 = [1, 4, 6, 4, 1] + ? binomial('x, 2) + %3 = 1/2*x^2 - 1/2*x + @eprog\noindent When $n$ is a negative integer and $k$ is negative, + we use Daniel Loeb's extension, + $$ \lim_{t\to 1} \Gamma(n+t) / \Gamma(k+t) / \Gamma(n-k+t). $$ + (Sets with a negative number of elements, \emph{Adv. Math.} {\bf 91} (1992), + no. 1, 64--74. See also~\kbd{https://arxiv.org/abs/1105.3689}.) + This way the symmetry relation $\binom{n}{k} = \binom{n}{n - k}$ + becomes valid for all integers $n$ and $k$, and + the binomial theorem + holds for all complex numbers $a$, $b$, $n$ with $|b| < |a|$: + $$ (a + b)^{n} = \sum_{k\geq 0} \binom{n}{k} a^{n-k} b^{k}\,. $$ + Beware that this extension is incompatible with another traditional + extension ($\binom{n}{k} := 0$ if $k < 0$); to enforce the latter, use + \bprog + BINOMIAL(n, k) = if (k >= 0, binomial(n, k)); + @eprog + + The argument $k$ may be omitted if $n$ is a + nonnegative integer; in this case, return the vector with $n+1$ + components whose $k+1$-th entry is \kbd{binomial}$(n,k)$ + \bprog + ? binomial(4) + %4 = [1, 4, 6, 4, 1] + @eprog + +Function: bitand +Class: basic +Section: conversions +C-Name: gbitand +Prototype: GG +Help: bitand(x,y): bitwise "and" of two integers x and y. Negative numbers + behave as if modulo big power of 2. +Description: + (small, small):small:parens $(1)&$(2) + (gen, gen):int gbitand($1, $2) +Doc: + bitwise \tet{and} + \sidx{bitwise and}of two integers $x$ and $y$, that is the integer + $$\sum_{i} (x_{i}~\kbd{and}~y_{i}) 2^{i}$$ + + Negative numbers behave $2$-adically, i.e.~the result is the $2$-adic limit + of \kbd{bitand}$(x_{n},y_{n})$, where $x_{n}$ and $y_{n}$ are nonnegative + integers tending to $x$ and $y$ respectively. (The result is an ordinary + integer, possibly negative.) + + \bprog + ? bitand(5, 3) + %1 = 1 + ? bitand(-5, 3) + %2 = 3 + ? bitand(-5, -3) + %3 = -7 + @eprog +Variant: Also available is + \fun{GEN}{ibitand}{GEN x, GEN y}, which returns the bitwise \emph{and} + of $|x|$ and $|y|$, two integers. + +Function: bitneg +Class: basic +Section: conversions +C-Name: gbitneg +Prototype: GD-1,L, +Help: bitneg(x,{n=-1}): bitwise negation of an integers x truncated to n + bits. n=-1 means represent infinite sequences of bit 1 as negative numbers. + Negative numbers behave as if modulo big power of 2. +Doc: + \idx{bitwise negation} of an integer $x$, + truncated to $n$ bits, $n\geq 0$, that is the integer + $$\sum_{i=0}^{n-1} \kbd{not}(x_{i}) 2^{i}.$$ + The special case $n=-1$ means no truncation: an infinite sequence of + leading $1$ is then represented as a negative number. + + See \secref{se:bitand} for the behavior for negative arguments. + +Function: bitnegimply +Class: basic +Section: conversions +C-Name: gbitnegimply +Prototype: GG +Help: bitnegimply(x,y): bitwise "negated imply" of two integers x and y, + in other words, x BITAND BITNEG(y). Negative numbers behave as if modulo big + power of 2. +Description: + (small, small):small:parens $(1)&~$(2) + (gen, gen):int gbitnegimply($1, $2) +Doc: + bitwise negated imply of two integers $x$ and + $y$ (or \kbd{not} $(x \Rightarrow y)$), that is the integer $$\sum + (x_{i}~\kbd{and not}(y_{i})) 2^{i}$$ + + See \secref{se:bitand} for the behavior for negative arguments. +Variant: Also available is + \fun{GEN}{ibitnegimply}{GEN x, GEN y}, which returns the bitwise negated + imply of $|x|$ and $|y|$, two integers. + +Function: bitor +Class: basic +Section: conversions +C-Name: gbitor +Prototype: GG +Help: bitor(x,y): bitwise "or" of two integers x and y. Negative numbers + behave as if modulo big power of 2. +Description: + (small, small):small:parens $(1)|$(2) + (gen, gen):int gbitor($1, $2) +Doc: + \sidx{bitwise inclusive or}bitwise (inclusive) + \tet{or} of two integers $x$ and $y$, that is the integer $$\sum + (x_{i}~\kbd{or}~y_{i}) 2^{i}$$ + + See \secref{se:bitand} for the behavior for negative arguments. +Variant: Also available is + \fun{GEN}{ibitor}{GEN x, GEN y}, which returns the bitwise \emph{or} + of $|x|$ and $|y|$, two integers. + +Function: bitprecision +Class: basic +Section: conversions +C-Name: bitprecision00 +Prototype: GDG +Help: bitprecision(x,{n}): if n is present and positive, return x at precision + n bits. If n is omitted, return real precision of object x in bits. +Doc: the function behaves differently according to whether $n$ is + present or not. If $n$ is missing, the function returns + the (floating point) precision in bits of the PARI object $x$. + + If $x$ is an exact object, the function returns \kbd{+oo}. + \bprog + ? bitprecision(exp(1e-100)) + %1 = 512 \\ 512 bits + ? bitprecision( [ exp(1e-100), 0.5 ] ) + %2 = 128 \\ minimal accuracy among components + ? bitprecision(2 + x) + %3 = +oo \\ exact object + @eprog\noindent Use \kbd{getlocalbitprec()} to retrieve the + working bit precision (as modified by possible \kbd{localbitprec} + statements). + + If $n$ is present and positive, the function creates a new object equal to $x$ + with the new bit-precision roughly $n$. In fact, the smallest multiple of 64 + (resp.~32 on a 32-bit machine) larger than or equal to $n$. + + For $x$ a vector or a matrix, the operation is + done componentwise; for series and polynomials, the operation is done + coefficientwise. For real $x$, $n$ is the number of desired significant + \emph{bits}. If $n$ is smaller than the precision of $x$, $x$ is truncated, + otherwise $x$ is extended with zeros. For exact or non-floating-point types, + no change. + \bprog + ? bitprecision(Pi, 10) \\ actually 64 bits ~ 19 decimal digits + %1 = 3.141592653589793239 + ? bitprecision(1, 10) + %2 = 1 + ? bitprecision(1 + O(x), 10) + %3 = 1 + O(x) + ? bitprecision(2 + O(3^5), 10) + %4 = 2 + O(3^5) + @eprog\noindent + +Function: bittest +Class: basic +Section: conversions +C-Name: gbittest +Prototype: GL +Help: bittest(x,n): gives bit number n (coefficient of 2^n) of the integer x. + Negative numbers behave as if modulo big power of 2. +Description: + (small, small):bool:parens ($(1)>>$(2))&1 + (int, small):bool bittest($1, $2) + (gen, small):gen gbittest($1, $2) +Doc: + outputs the $n^{\text{th}}$ bit of $x$ starting + from the right (i.e.~the coefficient of $2^{n}$ in the binary expansion of $x$). + The result is 0 or 1. For $x\ge1$, the highest 1-bit is at $n = + \kbd{logint}(x)$ (and bigger $n$ gives $0$). + \bprog + ? bittest(7, 0) + %1 = 1 \\ the bit 0 is 1 + ? bittest(7, 2) + %2 = 1 \\ the bit 2 is 1 + ? bittest(7, 3) + %3 = 0 \\ the bit 3 is 0 + @eprog\noindent + See \secref{se:bitand} for the behavior at negative arguments. +Variant: For a \typ{INT} $x$, the variant \fun{long}{bittest}{GEN x, long n} is + generally easier to use, and if furthermore $n\ge 0$ the low-level function + \fun{ulong}{int_bit}{GEN x, long n} returns \kbd{bittest(abs(x),n)}. + +Function: bitxor +Class: basic +Section: conversions +C-Name: gbitxor +Prototype: GG +Help: bitxor(x,y): bitwise "exclusive or" of two integers x and y. + Negative numbers behave as if modulo big power of 2. +Description: + (small, small):small:parens $(1)^$(2) + (gen, gen):int gbitxor($1, $2) +Doc: + bitwise (exclusive) \tet{or} + \sidx{bitwise exclusive or}of two integers $x$ and $y$, that is the integer + $$\sum (x_{i}~\kbd{xor}~y_{i}) 2^{i}$$ + + See \secref{se:bitand} for the behavior for negative arguments. +Variant: Also available is + \fun{GEN}{ibitxor}{GEN x, GEN y}, which returns the bitwise \emph{xor} + of $|x|$ and $|y|$, two integers. + +Function: bnfcertify +Class: basic +Section: number_fields +C-Name: bnfcertify0 +Prototype: lGD0,L, +Help: bnfcertify(bnf,{flag = 0}): certify the correctness (i.e. remove the GRH) + of the bnf data output by bnfinit. If flag is present, only certify that the + class group is a quotient of the one computed in bnf (much simpler in general). +Doc: $\var{bnf}$ being as output by + \kbd{bnfinit}, checks whether the result is correct, i.e.~whether it is + possible to remove the assumption of the Generalized Riemann + Hypothesis\sidx{GRH}. It is correct if and only if the answer is 1. If it is + incorrect, the program may output some error message, or loop indefinitely. + You can check its progress by increasing the debug level. The \var{bnf} + structure must contain the fundamental units: + \bprog + ? K = bnfinit(x^3+2^2^3+1); bnfcertify(K) + *** at top-level: K=bnfinit(x^3+2^2^3+1);bnfcertify(K) + *** ^------------- + *** bnfcertify: precision too low in makeunits [use bnfinit(,1)]. + ? K = bnfinit(x^3+2^2^3+1, 1); \\ include units + ? bnfcertify(K) + %3 = 1 + @eprog + + If $\fl$ is present, only certify that the class group is a quotient of the + one computed in bnf (much simpler in general); likewise, the computed units + may form a subgroup of the full unit group. In this variant, the units are + no longer needed: + \bprog + ? K = bnfinit(x^3+2^2^3+1); bnfcertify(K, 1) + %4 = 1 + @eprog +Variant: Also available is \fun{GEN}{bnfcertify}{GEN bnf} ($\fl=0$). + +Function: bnfdecodemodule +Class: basic +Section: number_fields +C-Name: decodemodule +Prototype: GG +Help: bnfdecodemodule(nf,m): given a coded module m as in bnrdisclist, + gives the true module. +Doc: if $m$ is a module as output in the + first component of an extension given by \kbd{bnrdisclist}, outputs the + true module. + \bprog + ? K = bnfinit(x^2+23); L = bnrdisclist(K, 10); s = L[2] + %1 = [[[Vecsmall([8]), Vecsmall([1])], [[0, 0, 0]]], + [[Vecsmall([9]), Vecsmall([1])], [[0, 0, 0]]]] + ? bnfdecodemodule(K, s[1][1]) + %2 = + [2 0] + + [0 1] + ? bnfdecodemodule(K,s[2][1]) + %3 = + [2 1] + + [0 1] + @eprog + +Function: bnfinit +Class: basic +Section: number_fields +C-Name: bnfinit0 +Prototype: GD0,L,DGp +Help: bnfinit(P,{flag=0},{tech=[]}): compute the necessary data for future + use in ideal and unit group computations, including fundamental units if + they are not too large. flag and tech are both optional. flag can be any of + 0: default, 1: include all data in algebraic form (compact units). + See manual for details about tech. +Description: + (gen):bnf:prec Buchall($1, 0, $prec) + (gen, 0):bnf:prec Buchall($1, 0, $prec) + (gen, 1):bnf:prec Buchall($1, nf_FORCE, $prec) + (gen, ?small, ?gen):bnf:prec bnfinit0($1, $2, $3, $prec) +Doc: initializes a + \kbd{bnf} structure. Used in programs such as \kbd{bnfisprincipal}, + \kbd{bnfisunit} or \kbd{bnfnarrow}. By default, the results are conditional + on the GRH, see \ref{se:GRHbnf}. The result is a + 10-component vector \var{bnf}. + + This implements \idx{Buchmann}'s sub-exponential algorithm for computing the + class group, the regulator and a system of \idx{fundamental units} of the + general algebraic number field $K$ defined by the irreducible polynomial $P$ + with integer coefficients. The meaning of $\fl$ is as follows: + + \item $\fl = 0$ (default). This is the historical behavior, kept for + compatibility reasons and speed. It has severe drawbacks but is likely to be + a little faster than the alternative, twice faster say, so only use it if + speed is paramount, you obtain a useful speed gain for the fields + under consideration, and you are only interested in the field invariants + such as the classgroup structure or its regulator. The computations involve + exact algebraic numbers which are replaced by floating point embeddings for + the sake of speed. If the precision is insufficient, \kbd{gp} may not be able + to compute fundamental units, nor to solve some discrete logarithm problems. + It \emph{may} be possible to increase the precision of the \kbd{bnf} + structure using \kbd{nfnewprec} but this may fail, in particular when + fundamental units are large. In short, the resulting \kbd{bnf} + structure is correct and contains useful information but later + function calls to \kbd{bnfisprincpal} or \kbd{bnrclassfield} may fail. + + When $\fl=1$, we keep an exact algebraic version of all floating point data + and this allows to guarantee that functions using the structure will always + succeed, as well as to compute the fundamental units exactly. The units are + computed in compact form, as a product of small $S$-units, possibly with + huge exponents. This flag also allows \kbd{bnfisprincipal} to compute + generators of principal ideals in factored form as well. Be warned that + expanding such products explicitly can take a very long time, but they can + easily be mapped to floating point or $\ell$-adic embeddings of bounded + accuracy, or to $K^{*}/(K^{*})^{\ell}$, and this is enough for applications. In + short, this flag should be used by default, unless you have a very good + reason for it, for instance building massive tables of class numbers, and + you do not care about units or the effect large units would have on your + computation. + + $\var{tech}$ is a technical vector (empty by default, see \ref{se:GRHbnf}). + Careful use of this parameter may speed up your computations, + but it is mostly obsolete and you should leave it alone. + + \smallskip + + The components of a \var{bnf} are technical. + In fact: \emph{never access a component directly, always use + a proper member function.} However, for the sake of completeness and internal + documentation, their description is as follows. We use the notations + explained in the book by H. Cohen, \emph{A Course in Computational Algebraic + Number Theory}, Graduate Texts in Maths \key{138}, Springer-Verlag, 1993, + Section 6.5, and subsection 6.5.5 in particular. + + $\var{bnf}[1]$ contains the matrix $W$, i.e.~the matrix in Hermite normal + form giving relations for the class group on prime ideal generators + $(\goth{p}_{i})_{1\le i\le r}$. + + $\var{bnf}[2]$ contains the matrix $B$, i.e.~the matrix containing the + expressions of the prime ideal factorbase in terms of the $\goth{p}_{i}$. + It is an $r\times c$ matrix. + + $\var{bnf}[3]$ contains the complex logarithmic embeddings of the system of + fundamental units which has been found. It is an + $(r_{1}+r_{2})\times(r_{1}+r_{2}-1)$ matrix. + + $\var{bnf}[4]$ contains the matrix $M''_{C}$ of Archimedean components of the + relations of the matrix $(W|B)$. + + $\var{bnf}[5]$ contains the prime factor base, i.e.~the list of prime + ideals used in finding the relations. + + $\var{bnf}[6]$ contains a dummy $0$. + + $\var{bnf}[7]$ or \kbd{\var{bnf}.nf} is equal to the number field data + $\var{nf}$ as would be given by \kbd{nfinit}. + + $\var{bnf}[8]$ is a vector containing the classgroup \kbd{\var{bnf}.clgp} + as a finite abelian group, the regulator \kbd{\var{bnf}.reg}, + the number of roots of unity and a generator \kbd{\var{bnf}.tu}, the + fundamental units \emph{in expanded form} \kbd{\var{bnf}.fu}. If the + fundamental units were omitted in the \var{bnf}, \kbd{\var{bnf}.fu} returns + the sentinel value $0$. If $\fl = 1$, this vector contain also algebraic + data corresponding to the fundamental units and to the discrete logarithm + problem (see \kbd{bnfisprincipal}). In particular, if $\fl = 1$ we may + \emph{only} know the units in factored form: the first call to + \kbd{\var{bnf}.fu} expands them, which may be very costly, then caches the + result. + + $\var{bnf}[9]$ is a vector used in \tet{bnfisprincipal} only + and obtained as follows. Let $D = U W V$ obtained by applying the + \idx{Smith normal form} algorithm to the matrix $W$ (= $\var{bnf}[1]$) and + let $U_{r}$ be the reduction of $U$ modulo $D$. The first elements of the + factorbase are given (in terms of \kbd{bnf.gen}) by the columns of $U_{r}$, + with Archimedean component $g_{a}$; let also $GD_{a}$ be the Archimedean + components of the generators of the (principal) ideals defined by the + \kbd{bnf.gen[i]\pow bnf.cyc[i]}. Then $\var{bnf}[9]=[U_{r}, g_{a}, GD_{a}]$, + followed by technical exact components which allow to recompute $g_{a}$ and + $GD_{a}$ to higher accuracy. + + $\var{bnf}[10]$ is by default unused and set equal to 0. This field is used + to store further information about the field as it becomes available, which + is rarely needed, hence would be too expensive to compute during the initial + \kbd{bnfinit} call. For instance, the generators of the principal ideals + \kbd{bnf.gen[i]\pow bnf.cyc[i]} (during a call to \tet{bnrisprincipal}), or + those corresponding to the relations in $W$ and $B$ (when the \kbd{bnf} + internal precision needs to be increased). +Variant: + Also available is \fun{GEN}{Buchall}{GEN P, long flag, long prec}, + corresponding to \kbd{tech = NULL}, where + $\fl$ is either $0$ (default) or \tet{nf_FORCE} (include all data in + algebraic form). The function + \fun{GEN}{Buchall_param}{GEN P, double c1, double c2, long nrpid, long flag, long prec} gives direct access to the technical parameters. + +Function: bnfisintnorm +Class: basic +Section: number_fields +C-Name: bnfisintnorm0 +Prototype: GGD0,L, +Help: bnfisintnorm(bnf,x,{flag=0}): compute a complete system of solutions (modulo + units of positive norm) of the absolute norm equation N(a)=x, where a + belongs to the maximal order of big number field bnf (if bnf is not + certified, this depends on GRH). If (optional) flag is set, allow returning + solutions in factored form. +Doc: computes a complete system of + solutions (modulo units of positive norm) of the absolute norm equation + $\Norm(a)=x$, + where $a$ is an integer in $\var{bnf}$. If $\var{bnf}$ has not been certified, + the correctness of the result depends on the validity of \idx{GRH}. + If (optional) flag is set, allow returning solutions in factored form, which + helps a lot when the fundamental units are large (equivalently, when \kbd{bnf.reg} + is large); having an exact algebraic $\var{bnf}$ from \kbd{bnfinit(,1)} is + necessary in this case, else setting the flag will mostly be a no-op. + + \bprog + ? bnf = bnfinit(x^4-2, 1); + ? bnfisintnorm(bnf,7) + %2 = [-x^2 + x - 1, x^2 + x + 1] + ? bnfisintnorm(bnf,-7) + %3 = [-x^3 - 1, x^3 + 2*x^2 + 2*x + 1] + + ? bnf = bnfinit(x^2-2305843005992468481, 1); + ? bnfisintnorm(bnf, 2305843008139952128) + \\ stack overflow with 100GB parisize + ? bnf.reg \\ fundamental unit is huge + %6 = 14054016.227457155120413774802385952043 + + ? v = bnfisintnorm(bnf, 2305843008139952128, 1); #v + %7 = 31 \\ succeeds instantly + ? s = v[1]; [type(s), matsize(s)] + %8 = ["t_MAT", [165, 2]] \\ solution 1 is a product of 165 factors + ? exponent(s[,2]) + %9 = 105 + @eprog\noindent The \emph{exponents} have $105$ bits, so there is indeed little + hope of writing down the solutions in expanded form. + + See also \tet{bnfisnorm}. +Variant: The function \fun{GEN}{bnfisintnormabs0}{GEN bnf, GEN a, long flag}, + where \kbd{bnf} is a true \var{bnf} structure, + returns a complete system of solutions modulo units of the absolute norm + equation $|\Norm(x)| = |a|$. As fast as \kbd{bnfisintnorm}, but solves + the two equations $\Norm(x) = \pm a$ simultaneously. The functions + \fun{GEN}{bnfisintnormabs}{GEN bnf, GEN a}, + \fun{GEN}{bnfisintnorm}{GEN bnf, GEN a} correspond to $\fl = 0$. + +Function: bnfisnorm +Class: basic +Section: number_fields +C-Name: bnfisnorm +Prototype: GGD1,L, +Help: bnfisnorm(bnf,x,{flag=1}): tries to tell whether x (in Q) is the norm + of some fractional y (in bnf). Returns a vector [a,b] where x=Norm(a)*b. + Looks for a solution which is a S-unit, with S a certain list of primes (in + bnf) containing (among others) all primes dividing x. If bnf is known to be + Galois, you may set flag=0 (in this case, x is a norm iff b=1). If flag is + nonzero the program adds to S all the primes: dividing flag if flag<0, or + less than flag if flag>0. The answer is guaranteed (i.e x norm iff b=1) + under GRH, if S contains all primes less than 4log(disc(Bnf))^2, where + Bnf is the Galois closure of bnf. +Doc: tries to tell whether the + rational number $x$ is the norm of some element y in $\var{bnf}$. Returns a + vector $[a,b]$ where $x=Norm(a)*b$. Looks for a solution which is an $S$-unit, + with $S$ a certain set of prime ideals containing (among others) all primes + dividing $x$. If $\var{bnf}$ is known to be \idx{Galois}, you may set $\fl=0$ + (in this case, $x$ is a norm iff $b=1$). If $\fl$ is nonzero the program adds + to $S$ the following prime ideals, depending on the sign of $\fl$. If $\fl>0$, + the ideals of norm less than $\fl$. And if $\fl<0$ the ideals dividing $\fl$. + + Assuming \idx{GRH}, the answer is guaranteed (i.e.~$x$ is a norm iff $b=1$), + if $S$ contains all primes less than $4\log(\disc(\var{Bnf}))^{2}$, where + $\var{Bnf}$ is the Galois closure of $\var{bnf}$. + + See also \tet{bnfisintnorm}. + +Function: bnfisprincipal +Class: basic +Section: number_fields +C-Name: bnfisprincipal0 +Prototype: GGD1,L, +Help: bnfisprincipal(bnf,x,{flag=1}): bnf being output by bnfinit, gives + [e,t], where e is the vector of exponents on the class group generators and + t is the generator of the resulting principal ideal. In particular x is + principal if and only if e is the zero vector. flag is optional, whose + binary digits mean 1: output [e,t] (only e if unset); 2: increase precision + until t can be computed (do not insist if unset); 4: return t in + factored form (compact representation). +Doc: $\var{bnf}$ being the \sidx{principal ideal} + number field data output by \kbd{bnfinit}, and $x$ being an ideal, this + function tests whether the ideal is principal or not. The result is more + complete than a simple true/false answer and solves a general discrete + logarithm problem. Assume the class group is $\oplus (\Z/d_{i}\Z)g_{i}$ + (where the generators $g_{i}$ and their orders $d_{i}$ are respectively + given by \kbd{bnf.gen} and \kbd{bnf.cyc}). The routine returns a row vector + $[e,t]$, where $e$ is a vector of exponents $0 \leq e_{i} < d_{i}$, and $t$ + is a number field element such that + $$ x = (t) \prod_{i} g_{i}^{e_{i}}.$$ + For \emph{given} $g_{i}$ (i.e. for a given \kbd{bnf}), the $e_{i}$ are unique, + and $t$ is unique modulo units. + + In particular, $x$ is principal if and only if $e$ is the zero vector. Note + that the empty vector, which is returned when the class number is $1$, is + considered to be a zero vector (of dimension $0$). + \bprog + ? K = bnfinit(y^2+23); + ? K.cyc + %2 = [3] + ? K.gen + %3 = [[2, 0; 0, 1]] \\ a prime ideal above 2 + ? P = idealprimedec(K,3)[1]; \\ a prime ideal above 3 + ? v = bnfisprincipal(K, P) + %5 = [[2]~, [3/4, 1/4]~] + ? idealmul(K, v[2], idealfactorback(K, K.gen, v[1])) + %6 = + [3 0] + + [0 1] + ? % == idealhnf(K, P) + %7 = 1 + @eprog + + \noindent The binary digits of $\fl$ mean: + + \item $1$: If set, outputs $[e,t]$ as explained above, otherwise returns + only $e$, which is easier to compute. The following idiom only tests + whether an ideal is principal: + \bprog + is_principal(bnf, x) = !bnfisprincipal(bnf,x,0); + @eprog + + \item $2$: It may not be possible to recover $t$, given the initial accuracy + to which the \kbd{bnf} structure was computed. In that case, a warning is + printed and $t$ is set equal to the empty vector \kbd{[]\til}. If this bit is + set, increase the precision and recompute needed quantities until $t$ can be + computed. Warning: setting this may induce \emph{lengthy} computations, and + the result may be too large to be physically representable in any case. + You should consider using $\fl=4$ instead. + + \item $4$: Return $t$ in factored form (compact representation), + as a small product of $S$-units for a small set of finite places $S$, + possibly with huge exponents. This kind of result can be cheaply mapped to + $K^{*}/(K^{*})^{\ell}$ or to $\C$ or $\Q_{p}$ to bounded accuracy and this + is usually enough for applications. Explicitly expanding such a compact + representation is possible using \kbd{nffactorback} but may be \emph{very} + costly. The algorithm is guaranteed to succeed if the \kbd{bnf} was computed + using \kbd{bnfinit(,1)}. If not, the algorithm may fail to compute a huge + generator in this case (and replace it by \kbd{[]\til}). This is orders of + magnitude faster than $\fl=2$ when the generators are indeed large. +Variant: Instead of the above hardcoded numerical flags, one should + rather use an or-ed combination of the symbolic flags \tet{nf_GEN} (include + generators, possibly a place holder if too difficult), \tet{nf_GENMAT} + (include generators in compact form) and + \tet{nf_FORCE} (insist on finding the generators, a no-op if \tet{nf_GENMAT} + is included). + +Function: bnfissunit +Class: basic +Section: number_fields +C-Name: bnfissunit +Prototype: GGG +Obsolete: 2020-01-15 +Help: bnfissunit(bnf,sfu,x): this function is obsolete, use bnfisunit. +Doc: this function is obsolete, use \kbd{bnfisunit}. + +Function: bnfisunit +Class: basic +Section: number_fields +C-Name: bnfisunit0 +Prototype: GGDG +Help: bnfisunit(bnf,x,{U}): bnf being output by bnfinit, give + the column vector of exponents of x on the fundamental units and the roots + of unity if x is a unit, the empty vector otherwise. If U is present, + as given by bnfunits, decompose x on the attached S-units generators. +Doc: \var{bnf} being the number field data + output by \kbd{bnfinit} and $x$ being an algebraic number (type integer, + rational or polmod), this outputs the decomposition of $x$ on the fundamental + units and the roots of unity if $x$ is a unit, the empty vector otherwise. + More precisely, if $u_{1}$,\dots,$u_{r}$ are the fundamental units, and $\zeta$ + is the generator of the group of roots of unity (\kbd{bnf.tu}), the output is + a vector $[x_{1},\dots,x_{r},x_{r+1}]$ such that $x=u_{1}^{x_{1}}\cdots + u_{r}^{x_{r}}\cdot\zeta^{x_{r+1}}$. The $x_{i}$ are integers but the last one + ($i = r+1$) is only defined modulo the order $w$ of $\zeta$ and is guaranteed + to be in $[0,w[$. + + Note that \var{bnf} need not contain the fundamental units explicitly: it may + contain the placeholder $0$ instead: + \bprog + ? setrand(1); bnf = bnfinit(x^2-x-100000); + ? bnf.fu + %2 = 0 + ? u = [119836165644250789990462835950022871665178127611316131167, \ + 379554884019013781006303254896369154068336082609238336]~; + ? bnfisunit(bnf, u) + %3 = [-1, 0]~ + @eprog\noindent The given $u$ is $1/u_{1}$, where $u_{1}$ is the fundamental + unit implicitly stored in \var{bnf}. In this case, $u_{1}$ was not computed + and stored in algebraic form since the default accuracy was too low. Re-run + the \kbd{bnfinit} command at \kbd{\bs g1} or higher to see such diagnostics. + + This function allows $x$ to be given in factored form, but it then assumes + that $x$ is an actual unit. (Because it is general too costly to check + whether this is the case.) + \bprog + ? { v = [2, 85; 5, -71; 13, -162; 17, -76; 23, -37; 29, -104; [224, 1]~, -66; + [-86, 1]~, 86; [-241, 1]~, -20; [44, 1]~, 30; [124, 1]~, 11; [125, -1]~, -11; + [-214, 1]~, 33; [-213, -1]~, -33; [189, 1]~, 74; [190, -1]~, 104; + [-168, 1]~, 2; [-167, -1]~, -8]; } + ? bnfisunit(bnf,v) + %5 = [1, 0]~ + @eprog\noindent Note that $v$ is the fundamental unit of \kbd{bnf} given in + compact (factored) form. + + If the argument \kbd{U} is present, as output by \kbd{bnfunits(bnf, S)}, + then the function decomposes $x$ on the $S$-units generators given in + \kbd{U[1]}. + \bprog + ? bnf = bnfinit(x^4 - x^3 + 4*x^2 + 3*x + 9, 1); + ? bnf.sign + %2 = [0, 2] + ? S = idealprimedec(bnf,5); #S + %3 = 2 + ? US = bnfunits(bnf,S); + ? g = US[1]; #g \\ #S = #g, four S-units generators, in factored form + %5 = 4 + ? g[1] + %6 = [[6, -3, -2, -2]~ 1] + ? g[2] + %7 = + [[-1, 1/2, -1/2, -1/2]~ 1] + + [ [4, -2, -1, -1]~ 1] + ? [nffactorback(bnf, x) | x <- g] + %8 = [[6, -3, -2, -2]~, [-5, 5, 0, 0]~, [-1, 1, -1, 0]~, + [1, -1, 0, 0]~] + + ? u = [10,-40,24,11]~; + ? a = bnfisunit(bnf, u, US) + %9 = [2, 0, 1, 4]~ + ? nffactorback(bnf, g, a) \\ prod_i g[i]^a[i] still in factored form + %10 = + [[6, -3, -2, -2]~ 2] + + [ [0, 0, -1, -1]~ 1] + + [ [2, -1, -1, 0]~ -2] + + [ [1, 1, 0, 0]~ 2] + + [ [-1, 1, 1, 1]~ -1] + + [ [1, -1, 0, 0]~ 4] + + ? nffactorback(bnf,%) \\ u = prod_i g[i]^a[i] + %11 = [10, -40, 24, 11]~ + @eprog +Variant: Also available is \fun{GEN}{bnfisunit}{GEN bnf, GEN x} for $U = + \kbd{NULL}$. + +Function: bnflog +Class: basic +Section: number_fields +C-Name: bnflog +Prototype: GG +Help: bnflog(bnf,l): let bnf be attached to a number field F and let l be + a prime number. Return the logarithmic l-class group Cl~_F. +Doc: let \var{bnf} be a \var{bnf} structure attached to the number field $F$ and let $l$ be + a prime number (hereafter denoted $\ell$ for typographical reasons). Return + the logarithmic $\ell$-class group $\widetilde{Cl}_{F}$ + of $F$. This is an abelian group, conjecturally finite (known to be finite + if $F/\Q$ is abelian). The function returns if and only if + the group is indeed finite (otherwise it would run into an infinite loop). + Let $S = \{ \goth{p}_{1},\dots, \goth{p}_{k}\}$ be the set of $\ell$-adic places + (maximal ideals containing $\ell$). + The function returns $[D, G(\ell), G']$, where + + \item $D$ is the vector of elementary divisors for $\widetilde{Cl}_{F}$. + + \item $G(\ell)$ is the vector of elementary divisors for + the (conjecturally finite) abelian group + $$\widetilde{\Cl}(\ell) = + \{ \goth{a} = \sum_{i \leq k} a_{i} \goth{p}_{i} :~\deg_{F} \goth{a} = 0\},$$ + where the $\goth{p}_{i}$ are the $\ell$-adic places of $F$; this is a + subgroup of $\widetilde{\Cl}$. + + \item $G'$ is the vector of elementary divisors for the $\ell$-Sylow $Cl'$ + of the $S$-class group of $F$; the group $\widetilde{\Cl}$ maps to $Cl'$ + with a simple co-kernel. + +Function: bnflogdegree +Class: basic +Section: number_fields +C-Name: bnflogdegree +Prototype: GGG +Help: bnflogdegree(nf,A,l): let A be an ideal, return exp(deg_F A) + the exponential of the l-adic logarithmic degree. +Doc: Let \var{nf} be a \var{nf} structure attached to a number field $F$, + and let $l$ be a prime number (hereafter + denoted $\ell$). The + $\ell$-adified group of id\`{e}les of $F$ quotiented by + the group of logarithmic units is identified to the $\ell$-group + of logarithmic divisors $\oplus \Z_{\ell} [\goth{p}]$, generated by the + maximal ideals of $F$. + + The \emph{degree} map $\deg_{F}$ is additive with values in $\Z_{\ell}$, + defined by $\deg_{F} \goth{p} = \tilde{f}_{\goth{p}} \deg_{\ell} p$, + where the integer $\tilde{f}_{\goth{p}}$ is as in \tet{bnflogef} and + $\deg_{\ell} p$ + is $\log_{\ell} p$ for $p\neq \ell$, $\log_{\ell} (1 + \ell)$ for + $p = \ell\neq 2$ and $\log_{\ell} (1 + 2^{2})$ for $p = \ell = 2$. + + Let $A = \prod \goth{p}^{n_{\goth{p}}}$ be an ideal and let $\tilde{A} = + \sum n_{\goth{p}} [\goth{p}]$ be the attached logarithmic divisor. Return the + exponential of the $\ell$-adic logarithmic degree $\deg_{F} A$, which is a + natural number. + +Function: bnflogef +Class: basic +Section: number_fields +C-Name: bnflogef +Prototype: GG +Help: bnflogef(nf,pr): return [e~, f~] the logarithmic ramification and + residue degrees for the maximal ideal pr. +Doc: let \var{nf} be a \var{nf} structure attached to a number field $F$ + and let \var{pr} be a \var{prid} structure attached to a + maximal ideal $\goth{p} / p$. Return + $[\tilde{e}(F_{\goth{p}} / \Q_{p}), \tilde{f}(F_{\goth{p}} / \Q_{p})]$ + the logarithmic ramification and residue degrees. Let $\Q_{p}^{c}/\Q_{p}$ + be the cyclotomic $\Z_{p}$-extension, then + $\tilde{e} = [F_{\goth{p}} \colon F_{\goth{p}} \cap \Q_{p}^{c}]$ and + $\tilde{f} = [F_{\goth{p}} \cap \Q_{p}^{c} \colon \Q_{p}]$. Note that + $\tilde{e}\tilde{f} = e(\goth{p}/p) f(\goth{p}/p)$, where $e(\goth{p}/p)$ and $f(\goth{p}/p)$ denote the + usual ramification and residue degrees. + \bprog + ? F = nfinit(y^6 - 3*y^5 + 5*y^3 - 3*y + 1); + ? bnflogef(F, idealprimedec(F,2)[1]) + %2 = [6, 1] + ? bnflogef(F, idealprimedec(F,5)[1]) + %3 = [1, 2] + @eprog + +Function: bnfnarrow +Class: basic +Section: number_fields +C-Name: bnfnarrow +Prototype: G +Help: bnfnarrow(bnf): given a big number field as output by bnfinit, gives + as a 3-component vector the structure of the narrow class group. +Doc: \var{bnf} being as output by + \kbd{bnfinit}, computes the narrow class group of \var{bnf}. The output is + a 3-component row vector $v$ analogous to the corresponding class group + component \kbd{\var{bnf}.clgp}: the first component + is the narrow class number \kbd{$v$.no}, the second component is a vector + containing the SNF\sidx{Smith normal form} cyclic components \kbd{$v$.cyc} of + the narrow class group, and the third is a vector giving the generators of + the corresponding \kbd{$v$.gen} cyclic groups. Note that this function is a + special case of \kbd{bnrinit}; the \var{bnf} need not contain fundamental + units. + +Function: bnfsignunit +Class: basic +Section: number_fields +C-Name: signunits +Prototype: G +Help: bnfsignunit(bnf): matrix of signs of the real embeddings of the system + of fundamental units found by bnfinit. +Doc: $\var{bnf}$ being as output by + \kbd{bnfinit}, this computes an $r_{1}\times(r_{1}+r_{2}-1)$ matrix having + $\pm1$ + components, giving the signs of the real embeddings of the fundamental units. + The following functions compute generators for the totally positive units: + \bprog + /* exponents of totally positive units generators on K.tu, K.fu */ + tpuexpo(K)= + { my(M, S = bnfsignunit(K), [m,n] = matsize(S)); + \\ m = K.r1, n = r1+r2-1 + S = matrix(m,n, i,j, if (S[i,j] < 0, 1,0)); + S = concat(vectorv(m,i,1), S); \\ add sign(-1) + M = matkermod(S, 2); + if (M, mathnfmodid(M, 2), 2*matid(n+1)) + } + + /* totally positive fundamental units of bnf K */ + tpu(K)= + { my(ex = tpuexpo(K)[,^1]); \\ remove ex[,1], corresponds to 1 or -1 + my(v = concat(K.tu[2], K.fu)); + [ nffactorback(K, v, c) | c <- ex]; + } + @eprog + +Function: bnfsunit +Class: basic +Section: number_fields +C-Name: bnfsunit +Prototype: GGp +Help: bnfsunit(bnf,S): compute the fundamental S-units of the number field + bnf output by bnfinit, S being a list of prime ideals. res[1] contains the + S-units, res[5] the S-classgroup. +Doc: computes the fundamental $S$-units of the + number field $\var{bnf}$ (output by \kbd{bnfinit}), where $S$ is a list of + prime ideals (output by \kbd{idealprimedec}). The output is a vector $v$ with + 6 components. + + $v[1]$ gives a minimal system of (integral) generators of the $S$-unit group + modulo the unit group. + + $v[2]$ contains technical data needed by \kbd{bnfissunit}. + + $v[3]$ is an obsoleted component, now the empty vector. + + $v[4]$ is the $S$-regulator (this is the product of the regulator, the + $S$-class number and the natural logarithms of the norms of the ideals + in $S$). + + $v[5]$ gives the $S$-class group structure, in the usual abelian group + format: a vector whose three components give in order the $S$-class number, + the cyclic components and the generators. + + $v[6]$ is a copy of $S$. +Variant: Also available is + \fun{GEN}{sunits_mod_units}{GEN bnf, GEN S} which returns only $v[1]$. + +Function: bnfunits +Class: basic +Section: number_fields +C-Name: bnfunits +Prototype: GDG +Help: bnfunits(bnf,{S}): return the fundamental units of the number field + bnf output by bnfinit; if S is present and is a list of prime ideals, compute + fundamental S-units instead. The first component of the result contains the + S-units, followed by fundamental units, followed by the torsion unit. + The result may be used as an optional argument to bnfisunit. +Doc: return the fundamental units of the number field + bnf output by bnfinit; if $S$ is present and is a list of prime ideals, + compute fundamental $S$-units instead. The first component of the result + contains independent integral $S$-units generators: first nonunits, then + $r_{1}+r_{2}-1$ fundamental units, then the torsion unit. The result may be + used + as an optional argument to bnfisunit. The units are given in compact form: + no expensive computation is attempted if the \var{bnf} does not already + contain units. + + \bprog + ? bnf = bnfinit(x^4 - x^3 + 4*x^2 + 3*x + 9, 1); + ? bnf.sign \\ r1 + r2 - 1 = 1 + %2 = [0, 2] + ? U = bnfunits(bnf); u = U[1]; + ? #u \\ r1 + r2 = 2 units + %5 = 2; + ? u[1] \\ fundamental unit as factorization matrix + %6 = + [[0, 0, -1, -1]~ 1] + + [[2, -1, -1, 0]~ -2] + + [ [1, 1, 0, 0]~ 2] + + [ [-1, 1, 1, 1]~ -1] + ? u[2] \\ torsion unit as factorization matrix + %7 = + [[1, -1, 0, 0]~ 1] + ? [nffactorback(bnf, z) | z <- u] \\ same units in expanded form + %8 = [[-1, 1, -1, 0]~, [1, -1, 0, 0]~] + @eprog + + Now an example involving $S$-units for a nontrivial $S$: + \bprog + ? S = idealprimedec(bnf,5); #S + %9 = 2 + ? US = bnfunits(bnf, S); uS = US[1]; + ? g = [nffactorback(bnf, z) | z <- uS] \\ now 4 units + %11 = [[6, -3, -2, -2]~, [-5, 5, 0, 0]~, [-1, 1, -1, 0]~, [1, -1, 0, 0]~] + ? bnfisunit(bnf,[10,-40,24,11]~) + %12 = []~ \\ not a unit + ? e = bnfisunit(bnf, [10,-40,24,11]~, US) + %13 = [2, 0, 1, 4]~ \\ ...but an S-unit + ? nffactorback(bnf, g, e) + %14 = [10, -40, 24, 11]~ + ? nffactorback(bnf, uS, e) \\ in factored form + %15 = + [[6, -3, -2, -2]~ 2] + + [ [0, 0, -1, -1]~ 1] + + [ [2, -1, -1, 0]~ -2] + + [ [1, 1, 0, 0]~ 2] + + [ [-1, 1, 1, 1]~ -1] + + [ [1, -1, 0, 0]~ 4] + @eprog\noindent Note that in more complicated cases, any \kbd{nffactorback} + fully expanding an element in factored form could be \emph{very} expensive. + On the other hand, the final example expands a factorization whose components + are themselves in factored form, hence the result is a factored form: + this is a cheap operation. + +Function: bnrL1 +Class: basic +Section: number_fields +C-Name: bnrL1 +Prototype: GDGD0,L,p +Help: bnrL1(bnr,{H},{flag=0}): bnr being output by bnrinit and + H being a square matrix defining a congruence subgroup of bnr (the + trivial subgroup if omitted), for each character of bnr trivial on this + subgroup, compute L(1, chi) (or equivalently the first nonzero term c(chi) + of the expansion at s = 0). The binary digits of flag mean 1: if 0 then + compute the term c(chi) and return [r(chi), c(chi)] where r(chi) is the + order of L(s, chi) at s = 0, or if 1 then compute the value at s = 1 (and in + this case, only for nontrivial characters), 2: if 0 then compute the value + of the primitive L-function attached to chi, if 1 then compute the value + of the L-function L_S(s, chi) where S is the set of places dividing the + modulus of bnr (and the infinite places), 3: return also the characters. +Doc: let \var{bnr} be the number field data output by \kbd{bnrinit} and + \var{H} be a square matrix defining a congruence subgroup of the + ray class group corresponding to \var{bnr} (the trivial congruence subgroup + if omitted). This function returns, for each \idx{character} $\chi$ of the ray + class group which is trivial on $H$, the value at $s = 1$ (or $s = 0$) of the + abelian $L$-function attached to $\chi$. For the value at $s = 0$, the + function returns in fact for each $\chi$ a vector $[r_{\chi}, c_{\chi}]$ where + $$L(s, \chi) = c \cdot s^{r} + O(s^{r + 1})$$ + \noindent near $0$. + + The argument \fl\ is optional, its binary digits + mean 1: compute at $s = 0$ if unset or $s = 1$ if set, 2: compute the + primitive $L$-function attached to $\chi$ if unset or the $L$-function + with Euler factors at prime ideals dividing the modulus of \var{bnr} removed + if set (that is $L_{S}(s, \chi)$, where $S$ is the + set of infinite places of the number field together with the finite prime + ideals dividing the modulus of \var{bnr}), 3: return also the character if + set. + \bprog + K = bnfinit(x^2-229); + bnr = bnrinit(K,1); + bnrL1(bnr) + @eprog\noindent + returns the order and the first nonzero term of $L(s, \chi)$ at $s = 0$ + where $\chi$ runs through the characters of the class group of + $K = \Q(\sqrt{229})$. Then + \bprog + bnr2 = bnrinit(K,2); + bnrL1(bnr2,,2) + @eprog\noindent + returns the order and the first nonzero terms of $L_{S}(s, \chi)$ at $s = 0$ + where $\chi$ runs through the characters of the class group of $K$ and $S$ is + the set of infinite places of $K$ together with the finite prime $2$. Note + that the ray class group modulo $2$ is in fact the class group, so + \kbd{bnrL1(bnr2,0)} returns the same answer as \kbd{bnrL1(bnr,0)}. + + This function will fail with the message + \bprog + *** bnrL1: overflow in zeta_get_N0 [need too many primes]. + @eprog\noindent if the approximate functional equation requires us to sum + too many terms (if the discriminant of $K$ is too large). + +Function: bnrchar +Class: basic +Section: number_fields +C-Name: bnrchar +Prototype: GGDG +Help: bnrchar(G,g,{v}): returns all characters chi on G such that + chi(g[i]) = e(v[i]); if v is omitted, returns all characters that are + trivial on the g[i]. +Doc: returns all characters $\chi$ on $G$ such that + $\chi(g_{i}) = e(v_{i})$, where $e(x) = \exp(2i\pi x)$. $G$ is allowed to be a + \var{bnr} struct (representing a ray class group) or a \var{znstar} + (representing $(\Z/N\Z)^{*}$). If $v$ is omitted, + returns all characters that are trivial on the $g_{i}$. Else the vectors $g$ + and $v$ must have the same length, the $g_{i}$ must be elements of $G$, and + each $v_{i}$ is a rational number whose denominator must divide the order of + $g_{i}$ in $G$. + + For convenience, the vector of the $g_{i}$ + can be replaced by a matrix whose columns give their discrete logarithm + in $G$, for instance as given by \kbd{bnrisprincipal} if $G$ is a \var{bnr}; + in this particular case, $G$ can be any finite abelian group + given by a vector of elementary divisors. + + \bprog + ? G = bnrinit(bnfinit(x), [160,[1]], 1); /* (Z/160Z)^* */ + ? G.cyc + %2 = [8, 4, 2] + ? g = G.gen; + ? bnrchar(G, g, [1/2,0,0]) + %4 = [[4, 0, 0]] \\ a unique character + ? bnrchar(G, [g[1],g[3]]) \\ all characters trivial on g[1] and g[3] + %5 = [[0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 0, 0]] + ? bnrchar(G, [1,0,0;0,1,0;0,0,2]) + %6 = [[0, 0, 1], [0, 0, 0]] \\ characters trivial on given subgroup + + ? G = znstar(75, 1); + ? bnrchar(G, [2, 7], [11/20, 1/4]) + %8 = [[1, 1]] \\ Dirichlet char: chi(2) = e(11/20), chi(7) = e(1/4) + @eprog + +Function: bnrclassfield +Class: basic +Section: number_fields +C-Name: bnrclassfield +Prototype: GDGD0,L,p +Help: bnrclassfield(bnr,{subgp},{flag=0}): bnr being as output by bnrinit, + find a relative equation for the class field corresponding to the congruence + subgroup described by (bnr,subgp). If flag=0, return a vector of polynomials + such that the compositum of the corresponding fields is the class field; if + flag=1 return a single relative polynomial; if flag=2 return a single + absolute polynomial. +Doc: \var{bnr} being as output by \kbd{bnrinit}, returns a relative equation + for the class field corresponding to the congruence group defined by + $(\var{bnr},\var{subgp})$ (the full ray class field if \var{subgp} is + omitted). The subgroup can also be a \typ{INT}~$n$, + meaning~$n \cdot \text{Cl}_{f}$. The function also handles a vector of + subgroup, e.g, from \tet{subgrouplist} and returns the vector of individual + results in this case. + + If $\fl=0$, returns a vector of polynomials such that the compositum of the + corresponding fields is the class field; if $\fl=1$ returns a single + polynomial; if $\fl=2$ returns a single absolute polynomial. + + \bprog + ? bnf = bnfinit(y^3+14*y-1); bnf.cyc + %1 = [4, 2] + ? pol = bnrclassfield(bnf,,1) \\ Hilbert class field + %2 = x^8 - 2*x^7 + ... + Mod(11*y^2 - 82*y + 116, y^3 + 14*y - 1) + ? rnfdisc(bnf,pol)[1] + %3 = 1 + ? bnr = bnrinit(bnf,3*5*7); bnr.cyc + %4 = [24, 12, 12, 2] + ? bnrclassfield(bnr,2) \\ maximal 2-elementary subextension + %5 = [x^2 + (-21*y - 105), x^2 + (-5*y - 25), x^2 + (-y - 5), x^2 + (-y - 1)] + \\ quadratic extensions of maximal conductor + ? bnrclassfield(bnr, subgrouplist(bnr,[2])) + %6 = [[x^2 - 105], [x^2 + (-105*y^2 - 1260)], [x^2 + (-105*y - 525)], + [x^2 + (-105*y - 105)]] + ? #bnrclassfield(bnr,subgrouplist(bnr,[2],1)) \\ all quadratic extensions + %7 = 15 + @eprog\noindent When the subgroup contains $n \text{Cl}_{f}$, where $n$ is + fixed, it is advised to directly compute the \kbd{bnr} modulo $n$ to avoid + expensive discrete logarithms: + \bprog + ? bnf = bnfinit(y^2-5); p = 1594287814679644276013; + ? bnr = bnrinit(bnf,p); \\ very slow + time = 24,146 ms. + ? bnrclassfield(bnr, 2) \\ ... even though the result is trivial + %3 = [x^2 - 1594287814679644276013] + ? bnr2 = bnrinit(bnf,p,,2); \\ now fast + time = 1 ms. + ? bnrclassfield(bnr2, 2) + %5 = [x^2 - 1594287814679644276013] + @eprog\noindent This will save a lot of time when the modulus contains a + maximal ideal whose residue field is large. + +Function: bnrclassno +Class: basic +Section: number_fields +C-Name: bnrclassno0 +Prototype: GDGDG +Help: bnrclassno(A,{B},{C}): relative degree of the class field defined by + A,B,C. [A,{B},{C}] is of type [bnr], [bnr,subgroup], [bnf,modulus], + or [bnf,modulus,subgroup]. + Faster than bnrinit if only the ray class number is wanted. +Doc: + let $A$, $B$, $C$ define a class field $L$ over a ground field $K$ + (of type \kbd{[\var{bnr}]}, + \kbd{[\var{bnr}, \var{subgroup}]}, + or \kbd{[\var{bnf}, \var{modulus}]}, + or \kbd{[\var{bnf}, \var{modulus},\var{subgroup}]}, + \secref{se:CFT}); this function returns the relative degree $[L:K]$. + + In particular if $A$ is a \var{bnf} (with units), and $B$ a modulus, + this function returns the corresponding ray class number modulo $B$. + One can input the attached \var{bid} (with generators if the subgroup + $C$ is non trivial) for $B$ instead of the module itself, saving some time. + + This function is faster than \kbd{bnrinit} and should be used if only the + ray class number is desired. See \tet{bnrclassnolist} if you need ray class + numbers for all moduli less than some bound. +Variant: Also available is + \fun{GEN}{bnrclassno}{GEN bnf,GEN f} to compute the ray class number + modulo~$f$. + +Function: bnrclassnolist +Class: basic +Section: number_fields +C-Name: bnrclassnolist +Prototype: GG +Help: bnrclassnolist(bnf,list): if list is as output by ideallist or + similar, gives list of corresponding ray class numbers. +Doc: $\var{bnf}$ being as + output by \kbd{bnfinit}, and \var{list} being a list of moduli (with units) as + output by \kbd{ideallist} or \kbd{ideallistarch}, outputs the list of the + class numbers of the corresponding ray class groups. To compute a single + class number, \tet{bnrclassno} is more efficient. + + \bprog + ? bnf = bnfinit(x^2 - 2); + ? L = ideallist(bnf, 100, 2); + ? H = bnrclassnolist(bnf, L); + ? H[98] + %4 = [1, 3, 1] + ? l = L[1][98]; ids = vector(#l, i, l[i].mod[1]) + %5 = [[98, 88; 0, 1], [14, 0; 0, 7], [98, 10; 0, 1]] + @eprog + The weird \kbd{l[i].mod[1]}, is the first component of \kbd{l[i].mod}, i.e. + the finite part of the conductor. (This is cosmetic: since by construction + the Archimedean part is trivial, I do not want to see it). This tells us that + the ray class groups modulo the ideals of norm 98 (printed as \kbd{\%5}) have + respectively order $1$, $3$ and $1$. Indeed, we may check directly: + \bprog + ? bnrclassno(bnf, ids[2]) + %6 = 3 + @eprog + +Function: bnrcompositum +Class: basic +Section: number_fields +C-Name: bnrcompositum +Prototype: GG +Help: bnrcompositum(A,B): compositum [bnr,H] of the two abelian extensions + given by A = [bnr1,H1] and B = [bnr2,H2], where bnr1 and bnr2 are attached + to the same base field. +Doc: given two abelian extensions $A = \kbd{[bnr1, H1]}$ and + $B = \kbd{[bnr2, H2]}$, where \kbd{bnr1} and \kbd{bnr2} are two \kbd{bnr} + structures attached to the same base field, return their compositum + as \kbd{[bnr, H]}. The modulus attached to \kbd{bnr} need not be the + conductor of the compositum. + \bprog + ? Q = bnfinit(y); + ? bnr1 = bnrinit(Q, [7, [1]]); bnr1.cyc + %2 = [6] + ? bnr2 = bnrinit(Q, [13, [1]]); bnr2.cyc + %3 = [12] + ? H1 = Mat(2); bnrclassfield(bnr1, H1) + %4 = [x^2 + 7] + ? H2 = Mat(2); bnrclassfield(bnr2, H2) + %5 = [x^2 - 13] + ? [bnr,H] = bnrcompositum([bnr1, H1], [bnr2,H2]); + ? bnrclassfield(bnr,H) + %7 = [x^2 - 13, x^2 + 7] + @eprog + +Function: bnrconductor +Class: basic +Section: number_fields +C-Name: bnrconductor0 +Prototype: GDGDGD0,L, +Help: bnrconductor(A,{B},{C},{flag=0}): conductor f of the subfield of + the ray class field given by A,B,C. flag is optional and + can be 0: default, 1: returns [f, Cl_f, H], H subgroup of the ray class + group modulo f defining the extension, 2: returns [f, bnr(f), H]. +Doc: conductor $f$ of the subfield of a ray class field as defined by $[A,B,C]$ + (of type \kbd{[\var{bnr}]}, + \kbd{[\var{bnr}, \var{subgroup}]}, + \kbd{[\var{bnf}, \var{modulus}]} or + \kbd{[\var{bnf}, \var{modulus}, \var{subgroup}]}, + \secref{se:CFT}) + + If $\fl = 0$, returns $f$. + + If $\fl = 1$, returns $[f, Cl_{f}, H]$, where $Cl_{f}$ is the ray class group + modulo $f$, as a finite abelian group; finally $H$ is the subgroup of + $Cl_{f}$ defining the extension. + + If $\fl = 2$, returns $[f, \var{bnr}(f), H]$, as above except $Cl_{f}$ is + replaced by a \kbd{bnr} structure, as output by $\tet{bnrinit}(,f)$, without + generators unless the input contained a \var{bnr} with generators. + + In place of a subgroup $H$, this function also accepts a character + \kbd{chi} $=(a_{j})$, expressed as usual in terms of the generators + \kbd{bnr.gen}: $\chi(g_{j}) = \exp(2i\pi a_{j} / d_{j})$, where $g_{j}$ has + order $d_{j} = \kbd{bnr.cyc[j]}$. In which case, the function returns + respectively + + If $\fl = 0$, the conductor $f$ of $\text{Ker} \chi$. + + If $\fl = 1$, $[f, Cl_{f}, \chi_{f}]$, where $\chi_{f}$ is $\chi$ expressed + on the minimal ray class group, whose modulus is the conductor. + + If $\fl = 2$, $[f, \var{bnr}(f), \chi_{f}]$. + + \misctitle{Note} Using this function with $\fl \neq 0$ is usually a + bad idea and kept for compatibility and convenience only: $\fl = 1$ has + always been useless, since it is no faster than $\fl = 2$ and returns less + information; $\fl = 2$ is mostly OK with two subtle drawbacks: + + $\bullet$ it returns the full \var{bnr} attached to the full ray class + group, whereas in applications we only need $Cl_{f}$ modulo $N$-th powers, + where $N$ is any multiple of the exponent of $Cl_{f}/H$. Computing directly the + conductor, then calling \kbd{bnrinit} with optional argument $N$ avoids this + problem. + + $\bullet$ computing the \var{bnr} needs only be done once for each + conductor, which is not possible using this function. + + For maximal efficiency, the recommended procedure is as follows. Starting + from data (character or congruence subgroups) attached to a modulus $m$, + we can first compute the conductors using this function with default $\fl = + 0$. Then for all data with a common conductor $f \mid m$, compute (once!) the + \var{bnr} attached to $f$ using \kbd{bnrinit} (modulo $N$-th powers for + a suitable $N$!) and finally map original data to the new \var{bnr} using + \kbd{bnrmap}. +Variant: + Also available are \fun{GEN}{bnrconductor}{GEN bnr, GEN H, long flag} + and \fun{GEN}{bnrconductormod}{GEN bnr, GEN H, long flag, GEN cycmod} + which returns ray class groups modulo \kbd{cycmod}-th powers. + +Function: bnrconductorofchar +Class: basic +Section: number_fields +C-Name: bnrconductorofchar +Prototype: GG +Obsolete: 2015-11-11 +Help: bnrconductorofchar(bnr,chi): this function is obsolete, use bnrconductor. +Doc: This function is obsolete, use \tev{bnrconductor}. + +Function: bnrdisc +Class: basic +Section: number_fields +C-Name: bnrdisc0 +Prototype: GDGDGD0,L, +Help: bnrdisc(A,{B},{C},{flag=0}): absolute or relative [N,R1,discf] of + the field defined by A,B,C. [A,{B},{C}] is of type [bnr], + [bnr,subgroup], [bnf, modulus] or [bnf,modulus,subgroup], where bnf is as + output by bnfinit, bnr by bnrinit, and + subgroup is the HNF matrix of a subgroup of the corresponding ray class + group (if omitted, the trivial subgroup). flag is optional whose binary + digits mean 1: give relative data; 2: return 0 if modulus is not the + conductor. +Doc: $A$, $B$, $C$ defining a class field $L$ over a ground field $K$ + (of type \kbd{[\var{bnr}]}, + \kbd{[\var{bnr}, \var{subgroup}]}, + \kbd{[\var{bnr}, \var{character}]}, + \kbd{[\var{bnf}, \var{modulus}]} or + \kbd{[\var{bnf}, \var{modulus}, \var{subgroup}]}, + \secref{se:CFT}), outputs data $[N,r_{1},D]$ giving the discriminant and + signature of $L$, depending on the binary digits of \fl: + + \item 1: if this bit is unset, output absolute data related to $L/\Q$: + $N$ is the absolute degree $[L:\Q]$, $r_{1}$ the number of real places of $L$, + and $D$ the discriminant of $L/\Q$. Otherwise, output relative data for $L/K$: + $N$ is the relative degree $[L:K]$, $r_{1}$ is the number of real places of $K$ + unramified in $L$ (so that the number of real places of $L$ is equal to $r_{1}$ + times $N$), and $D$ is the relative discriminant ideal of $L/K$. + + \item 2: if this bit is set and if the modulus is not the conductor of $L$, + only return 0. + +Function: bnrdisclist +Class: basic +Section: number_fields +C-Name: bnrdisclist0 +Prototype: GGDG +Help: bnrdisclist(bnf,bound,{arch}): list of discriminants of + ray class fields of all conductors up to norm bound. + The ramified Archimedean places are given by arch; all possible values are + taken if arch is omitted. Supports the alternative syntax + bnrdisclist(bnf,list), where list is as output by ideallist or ideallistarch + (with units). +Doc: $\var{bnf}$ being as output by \kbd{bnfinit} (with units), computes a + list of discriminants of Abelian extensions of the number field by increasing + modulus norm up to bound \var{bound}. The ramified Archimedean places are + given by \var{arch}; all possible values are taken if \var{arch} is omitted. + + The alternative syntax $\kbd{bnrdisclist}(\var{bnf},\var{list})$ is + supported, where \var{list} is as output by \kbd{ideallist} or + \kbd{ideallistarch} (with units), in which case \var{arch} is disregarded. + + The output $v$ is a vector, where $v[k]$ is itself a vector $w$, whose length + is the number of ideals of norm $k$. + + \item We consider first the case where \var{arch} was specified. Each + component of $w$ corresponds to an ideal $m$ of norm $k$, and + gives invariants attached to the ray class field $L$ of $\var{bnf}$ of + conductor $[m, \var{arch}]$. Namely, each contains a vector $[m,d,r,D]$ with + the following meaning: $m$ is the prime ideal factorization of the modulus, + $d = [L:\Q]$ is the absolute degree of $L$, $r$ is the number of real places + of $L$, and $D$ is the factorization of its absolute discriminant. We set $d + = r = D = 0$ if $m$ is not the finite part of a conductor. + + \item If \var{arch} was omitted, all $t = 2^{r_{1}}$ possible values are taken + and a component of $w$ has the form + $[m, [[d_{1},r_{1},D_{1}], \dots, [d_{t},r_{t},D_{t}]]]$, + where $m$ is the finite part of the conductor as above, and + $[d_{i},r_{i},D_{i}]$ are the invariants of the ray class field of conductor + $[m,v_{i}]$, where $v_{i}$ is the $i$-th Archimedean component, ordered by + inverse lexicographic order; so $v_{1} = [0,\dots,0]$, $v_{2} = [1,0\dots,0]$, + etc. Again, we set $d_{i} = r_{i} = D_{i} = 0$ if $[m,v_{i}]$ + is not a conductor. + + Finally, each prime ideal $pr = [p,\alpha,e,f,\beta]$ in the prime + factorization $m$ is coded as the integer $p\cdot n^{2}+(f-1)\cdot n+(j-1)$, + where $n$ is the degree of the base field and $j$ is such that + + \kbd{pr = idealprimedec(\var{nf},p)[j]}. + + \noindent $m$ can be decoded using \tet{bnfdecodemodule}. + + Note that to compute such data for a single field, either \tet{bnrclassno} + or \tet{bnrdisc} are (much) more efficient. + +Function: bnrgaloisapply +Class: basic +Section: number_fields +C-Name: bnrgaloisapply +Prototype: GGG +Help: bnrgaloisapply(bnr,mat,H): apply the automorphism given by its matrix + mat to the congruence subgroup H given as a HNF matrix. The matrix mat can be + computed with bnrgaloismatrix. +Doc: apply the automorphism given by its matrix \var{mat} to the congruence + subgroup $H$ given as a HNF matrix. + The matrix \var{mat} can be computed with \tet{bnrgaloismatrix}. + +Function: bnrgaloismatrix +Class: basic +Section: number_fields +C-Name: bnrgaloismatrix +Prototype: GG +Help: bnrgaloismatrix(bnr,aut): return the matrix of the action of the + automorphism aut of the base field bnf.nf on the generators of the ray class + field bnr.gen; aut can be given as a polynomial, or a vector of automorphisms + or a galois group as output by galoisinit, in which case a vector of matrices + is returned (in the later case, only for the generators aut.gen). +Doc: return the matrix of the action of the automorphism \var{aut} of the base + field \kbd{bnf.nf} on the generators of the ray class field \kbd{bnr.gen}. + The automorphism + \var{aut} can be given as a polynomial, an algebraic number, or a vector of + automorphisms and must stabilize the modulus \kbd{bnr.mod}. We also + allow a Galois group as output by \kbd{galoisinit}, in which case a + vector of matrices is returned corresponding to the generators + \kbd{aut.gen}. + Note: This function only makes sense when the ray class field attached to + \var{bnr} is Galois, which is not checked. + + The generators \kbd{bnr.gen} need not be explicitly computed in the input + \var{bnr}, which saves time: the result is well defined in this case also. + + \bprog + ? K = bnfinit(a^4-3*a^2+253009); B = bnrinit(K,9); B.cyc + %1 = [8400, 12, 6, 3] + ? G = nfgaloisconj(K) + %2 = [-a, a, -1/503*a^3 + 3/503*a, 1/503*a^3 - 3/503*a]~ + ? bnrgaloismatrix(B, G[2]) \\ G[2] = Id ... + %3 = + [1 0 0 0] + + [0 1 0 0] + + [0 0 1 0] + + [0 0 0 1] + ? bnrgaloismatrix(B, G[3]) \\ automorphism of order 2 + %4 = + [799 0 0 2800] + + [ 0 7 0 4] + + [ 4 0 5 2] + + [ 0 0 0 2] + ? M = %^2; for (i=1, #B.cyc, M[i,] %= B.cyc[i]); M + %5 = \\ acts on ray class group as automorphism of order 2 + [1 0 0 0] + + [0 1 0 0] + + [0 0 1 0] + + [0 0 0 1] + @eprog + + See \kbd{bnrisgalois} for further examples. +Variant: When $aut$ is a polynomial or an algebraic number, + \fun{GEN}{bnrautmatrix}{GEN bnr, GEN aut} is available. + +Function: bnrinit +Class: basic +Section: number_fields +C-Name: bnrinitmod +Prototype: GGD0,L,DG +Help: bnrinit(bnf,f,{flag=0},{cycmod}): given a bnf as output by + bnfinit and a modulus f, initializes data + linked to the ray class group structure corresponding to this module. flag + is optional, and can be 0: default, 1: compute also the generators. If + the positive integer cycmod is present, only compute the ray class group + modulo cycmod-th powers. +Description: + (gen,gen,?small):bnr bnrinit0($1, $2, $3) +Doc: $\var{bnf}$ is as + output by \kbd{bnfinit} (including fundamental units), $f$ is a modulus, + initializes data linked to the ray class group structure corresponding to + this module, a so-called \kbd{bnr} structure. One can input the attached + \var{bid} with generators for $f$ instead of the module itself, saving some + time. (As in \tet{idealstar}, the finite part of the conductor may be given + by a factorization into prime ideals, as produced by \tet{idealfactor}.) + + If the positive integer \kbd{cycmod} is present, only compute the ray class + group modulo \kbd{cycmod}, which may save a lot of time when some maximal + ideals in $f$ have a huge residue field. In applications, we are given + a congruence subgroup $H$ and study the class field attached to + $\text{Cl}_{f}/H$. If that finite Abelian group has an exponent which divides + \kbd{cycmod}, then we have changed nothing theoretically, while trivializing + expensive discrete logs in residue fields (since computations can be + made modulo \kbd{cycmod}-th powers). This is useful in \kbd{bnrclassfield}, + for instance when computing $p$-elementary extensions. + + The following member functions are available + on the result: \kbd{.bnf} is the underlying \var{bnf}, + \kbd{.mod} the modulus, \kbd{.bid} the \kbd{bid} structure attached to the + modulus; finally, \kbd{.clgp}, \kbd{.no}, \kbd{.cyc}, \kbd{.gen} refer to the + ray class group (as a finite abelian group), its cardinality, its elementary + divisors, its generators (only computed if $\fl = 1$). + + The last group of functions are different from the members of the underlying + \var{bnf}, which refer to the class group; use \kbd{\var{bnr}.bnf.\var{xxx}} + to access these, e.g.~\kbd{\var{bnr}.bnf.cyc} to get the cyclic decomposition + of the class group. + + They are also different from the members of the underlying \var{bid}, which + refer to $(\Z_{K}/f)^{*}$; use \kbd{\var{bnr}.bid.\var{xxx}} to access these, + e.g.~\kbd{\var{bnr}.bid.no} to get $\phi(f)$. + + If $\fl=0$ (default), the generators of the ray class group are not + explicitly computed, which saves time. Hence \kbd{\var{bnr}.gen} would + produce an error. Note that implicit generators are still fixed and stored + in the \var{bnr} (and guaranteed to be the same for fixed \var{bnf} and + \var{bid} inputs), in terms of \kbd{bnr.bnf.gen} and \kbd{bnr.bid.gen}. + The computation which is not performed is the expansion of such products + in the ray class group so as to fix eplicit ideal representatives. + + If $\fl=1$, as the default, except that generators are computed. +Variant: Instead of the above hardcoded numerical flags, one should rather use + \fun{GEN}{Buchraymod}{GEN bnf, GEN module, long flag, GEN cycmod} + where an omitted \kbd{cycmod} is coded as \kbd{NULL} and $\fl$ is an or-ed + combination of \kbd{nf\_GEN} (include generators) and \kbd{nf\_INIT} (if + omitted, return just the cardinality of the ray class group and its structure), + possibly 0. Or simply + \fun{GEN}{Buchray}{GEN bnf, GEN module, long flag} + when \kbd{cycmod} is \kbd{NULL}. + +Function: bnrisconductor +Class: basic +Section: number_fields +C-Name: bnrisconductor0 +Prototype: lGDGDG +Help: bnrisconductor(A,{B},{C}): returns 1 if the modulus is the + conductor of the subfield of the ray class field given by A,B,C (see + bnrdisc), and 0 otherwise. Slightly faster than bnrconductor if this is the + only desired result. +Doc: fast variant of \kbd{bnrconductor}$(A,B,C)$; $A$, $B$, $C$ represent + an extension of the base field, given by class field theory + (see~\secref{se:CFT}). Outputs 1 if this modulus is the conductor, and 0 + otherwise. This is slightly faster than \kbd{bnrconductor} when the + character or subgroup is not primitive. + +Function: bnrisgalois +Class: basic +Section: number_fields +C-Name: bnrisgalois +Prototype: lGGG +Help: bnrisgalois(bnr,gal,H): check whether the class field attached to + the subgroup H is Galois over the subfield of bnr.nf fixed by the Galois + group gal, which can be given as output by galoisinit, or as a matrix or a + vector of matrices as output by bnrgaloismatrix. The ray class field + attached to bnr need to be Galois, which is not checked. +Doc: check whether the class field attached to the subgroup $H$ is Galois + over the subfield of \kbd{bnr.nf} fixed by the group \var{gal}, which can be + given as output by \tet{galoisinit}, or as a matrix or a vector of matrices as + output by \kbd{bnrgaloismatrix}, the second option being preferable, since it + saves the recomputation of the matrices. Note: The function assumes that the + ray class field attached to \var{bnr} is Galois, which is not checked. + + In the following example, we lists the congruence subgroups of subextension of + degree at most $3$ of the ray class field of conductor $9$ which are Galois + over the rationals. + + \bprog + ? K = bnfinit(a^4-3*a^2+253009); B = bnrinit(K,9); G = galoisinit(K); + ? [H | H<-subgrouplist(B,3), bnrisgalois(B,G,H)]; + time = 160 ms. + ? M = bnrgaloismatrix(B,G); + ? [H | H<-subgrouplist(B,3), bnrisgalois(B,M,H)] + time = 1 ms. + @eprog + The second computation is much faster since \kbd{bnrgaloismatrix(B,G)} is + computed only once. + +Function: bnrisprincipal +Class: basic +Section: number_fields +C-Name: bnrisprincipal +Prototype: GGD1,L, +Help: bnrisprincipal(bnr,x,{flag=1}): bnr being output by bnrinit and x + being an ideal coprime to bnr.mod, returns [v,alpha], where v is the vector + of exponents on the ray class group generators and alpha is the generator of + the resulting principal ideal. If (optional) flag is set to 0, output only v. +Doc: let \var{bnr} be the ray class group data output by + \kbd{bnrinit}$(,,1)$ and let $x$ be an ideal in any form, coprime + to the modulus $f = \kbd{bnr.mod}$. Solves the discrete logarithm problem + in the ray class group, with respect to the generators \kbd{bnr.gen}, + in a way similar to \tet{bnfisprincipal}. If $x$ is not coprime to the + modulus of \var{bnr} the result is undefined. Note that \var{bnr} need not + contain the ray class group generators, i.e.~it may be created with + \kbd{bnrinit}$(,,0)$; in that case, although \kbd{bnr.gen} is undefined, we + can still fix natural generators for the ray class group (in terms of the + generators in \kbd{bnr.bnf.gen} and \kbd{bnr.bid.gen}) and compute with + respect to them. + + The binary digits of $\fl$ (default $\fl = 1$) mean: + + \item $1$: If set returns a 2-component vector $[e,\alpha]$ where $e$ + is the vector of components of $x$ on the ray class group generators, + $\alpha$ is an element congruent to $1~\text{mod}^{*} f$ such that + $x = \alpha \prod_{i} g_{i}^{e_{i}}$. If unset, returns only $e$. + + \item $4$: If set, returns $[e,\alpha]$ where $\alpha$ is given in factored + form (compact representation). This is orders of magnitude faster. + + \bprog + ? K = bnfinit(x^2 - 30); bnr = bnrinit(K, [4, [1,1]]); + ? bnr.clgp \\ ray class group is isomorphic to Z/4 x Z/2 x Z/2 + %2 = [16, [4, 2, 2]] + ? P = idealprimedec(K, 3)[1]; \\ the ramified prime ideal above 3 + ? bnrisprincipal(bnr,P) \\ bnr.gen undefined ! + %5 = [[3, 0, 0]~, 9] + ? bnrisprincipal(bnr,P, 0) \\ omit principal part + %5 = [3, 0, 0]~ + ? bnr = bnrinit(bnr, bnr.bid, 1); \\ include explicit generators + ? bnrisprincipal(bnr,P) \\ ... alpha is different ! + %7 = [[3, 0, 0]~, 1/128625] + @eprog It may be surprising that the generator $\alpha$ is different + although the underlying \var{bnf} and \var{bid} are the same. This defines + unique generators for the ray class group as ideal \emph{classes}, whether + we use \kbd{bnrinit(,0)} or \kbd{bnrinit(,1)}. But the actual ideal + representatives (implicit if $\fl=0$, computed and stored in the + \var{bnr} if $\fl=1$) are in general different and this is what + happens here. Indeed, the implicit generators are naturally expressed + in terms of \kbd{bnr.bnf.gen} and \kbd{bnr.bid.gen} and \emph{then} + expanded and simplified (in the same ideal class) so that we obtain ideal + representatives for \kbd{bnr.gen} which are as simple as possible. + And indeed the quotient of the two $\alpha$ found is $1$ modulo the + conductor (and positive at the infinite places it contains), and this is the + only guaranteed property. + + Beware that, when \kbd{bnr} is generated using \kbd{bnrinit(, cycmod)}, the + results are given in $\text{Cl}_{f}$ modulo \kbd{cycmod}-th powers: + \bprog + ? bnr2 = bnrinit(K, bnr.mod,, 2); \\ modulo squares + ? bnr2.clgp + %9 = [8, [2, 2, 2]] \\ bnr.clgp tensored by Z/2Z + ? bnrisprincipal(bnr2,P, 0) + %10 = [1, 0, 0]~ + @eprog +Variant: Instead of hardcoded numerical flags, one should rather use + \fun{GEN}{isprincipalray}{GEN bnr, GEN x} for $\fl = 0$, and if you + want generators: + \bprog + bnrisprincipal(bnr, x, nf_GEN) + @eprog + Also available is + \fun{GEN}{bnrisprincipalmod}{GEN bnr, GEN x, GEN mod, long flag} + that returns the discrete logarithm of~$x$ modulo the~\typ{INT} + \kbd{mod}; the value~$\kbd{mod = NULL}$ is treated as~$0$ (full discrete + logarithm), and~$\fl=1$ is not allowed if~\kbd{mod} is set. + +Function: bnrmap +Class: basic +Section: number_fields +C-Name: bnrmap +Prototype: GG +Help: bnrmap(A,B): if A and B are bnr structures for the same bnf attached + to moduli mA and mB with mB | mA, return the canonical surjection from + A to B. Alternatively, if A is a map from bnrmap and B is a congruence + subgroup or ray class character modulo mA, return the corresponding object on + Cl(mB). +Doc: This function has two different uses: + + \item if $A$ and $B$ are \var{bnr} structures for the same \var{bnf} attached + to moduli $m_{A}$ and $m_{B}$ with $m_{B} \mid m_{A}$, return the canonical surjection + from $A$ to $B$, i.e. from the ray class group moodulo $m_{A}$ to the ray + class group modulo $m_{B}$. The map is coded by a triple + $[M,\var{cyc}_{A},\var{cyc}_{B}]$: + $M$ gives the image of the fixed ray class group generators of $A$ in + terms of the ones in $B$, $\var{cyc}_{A}$ and $\var{cyc}_{B}$ are the cyclic + structures \kbd{A.cyc} and \kbd{B.cyc} respectively. Note that this function + does \emph{not} need $A$ or $B$ to contain explicit generators for the ray + class groups: they may be created using \kbd{bnrinit(,0)}. + + If $B$ is only known modulo $N$-th powers (from \kbd{bnrinit(,N)}), the result + is correct provided $N$ is a multiple of the exponent of $A$. + + \item if $A$ is a projection map as above and $B$ is either a congruence + subgroup $H$, or a ray class character $\chi$, or a discrete logarithm + (from \kbd{bnrisprincipal}) modulo $m_{A}$ whose conductor + divides $m_{B}$, return the image of the subgroup (resp. the character, the + discrete logarighm) as defined modulo $m_{B}$. The main use of this variant is + to compute the primitive subgroup or character attached to a \var{bnr} modulo + their conductor. This is more efficient than \tet{bnrconductor} in two + respects: the \var{bnr} attached to the conductor need only be computed once + and, most importantly, the ray class group can be computed modulo $N$-th + powers, where $N$ is a multiple of the exponent of $\text{Cl}_{m_{A}} / H$ + (resp. + of the order of $\chi$). Whereas \kbd{bnrconductor} is specified to return a + \var{bnr} attached to the full ray class group, which may lead to untractable + discrete logarithms in the full ray class group instead of a tiny quotient. + +Function: bnrrootnumber +Class: basic +Section: number_fields +C-Name: bnrrootnumber +Prototype: GGD0,L,p +Help: bnrrootnumber(bnr,chi,{flag=0}): returns the so-called Artin Root + Number, i.e. the constant W appearing in the functional equation of the + Hecke L-function attached to chi. Set flag = 1 if the character is known + to be primitive. +Doc: if $\chi=\var{chi}$ is a + \idx{character} over \var{bnr}, not necessarily primitive, let + $L(s,\chi) = \sum_{id} \chi(id) N(id)^{-s}$ be the attached + \idx{Artin L-function}. Returns the so-called \idx{Artin root number}, i.e.~the + complex number $W(\chi)$ of modulus 1 such that + % + $$\Lambda(1-s,\chi) = W(\chi) \Lambda(s,\overline{\chi})$$ + % + \noindent where $\Lambda(s,\chi) = A(\chi)^{s/2}\gamma_{\chi}(s) L(s,\chi)$ is + the enlarged L-function attached to $L$. + + You can set $\fl=1$ if the character is known to be primitive. Example: + \bprog + bnf = bnfinit(x^2 - x - 57); + bnr = bnrinit(bnf, [7,[1,1]]); + bnrrootnumber(bnr, [2,1]) + @eprog\noindent + returns the root number of the character $\chi$ of + $\Cl_{7\infty_{1}\infty_{2}}(\Q(\sqrt{229}))$ defined by + $\chi(g_{1}^{a}g_{2}^{b}) + = \zeta_{1}^{2a}\zeta_{2}^{b}$. Here $g_{1}, g_{2}$ are the generators of the + ray-class group given by \kbd{bnr.gen} and $\zeta_{1} = e^{2i\pi/N_{1}}, + \zeta_{2} = e^{2i\pi/N_{2}}$ where $N_{1}, N_{2}$ are the orders of $g_{1}$ + and $g_{2}$ respectively ($N_{1}=6$ and $N_{2}=3$ as \kbd{bnr.cyc} readily + tells us). + +Function: bnrstark +Class: basic +Section: number_fields +C-Name: bnrstark +Prototype: GDGp +Help: bnrstark(bnr,{subgroup}): bnr being as output by + bnrinit, finds a relative equation for the class field corresponding to + the module in bnr and the given congruence subgroup (the trivial subgroup if + omitted) using Stark's units. The ground field and the class field must be + totally real. +Doc: \var{bnr} being as output by \kbd{bnrinit}, finds a relative equation + for the class field corresponding to the modulus in \var{bnr} and the given + congruence subgroup (as usual, omit $\var{subgroup}$ if you want the whole ray + class group). + + The main variable of \var{bnr} must not be $x$, and the ground field and the + class field must be totally real. When the base field is $\Q$, the vastly + simpler \tet{galoissubcyclo} is used instead. Here is an example: + \bprog + bnf = bnfinit(y^2 - 3); + bnr = bnrinit(bnf, 5); + bnrstark(bnr) + @eprog\noindent + returns the ray class field of $\Q(\sqrt{3})$ modulo $5$. Usually, one wants + to apply to the result one of + \bprog + rnfpolredbest(bnf, pol) \\@com compute a reduced relative polynomial + rnfpolredbest(bnf, pol, 2) \\@com compute a reduced absolute polynomial + @eprog + + The routine uses \idx{Stark units} and needs to find a suitable auxiliary + conductor, which may not exist when the class field is not cyclic over the + base. In this case \kbd{bnrstark} is allowed to return a vector of + polynomials defining \emph{independent} relative extensions, whose compositum + is the requested class field. We decided that it was useful to keep the + extra information thus made available, hence the user has to take the + compositum herself, see \kbd{nfcompositum}. + + Even if it exists, the auxiliary conductor may be so large that later + computations become unfeasible. (And of course, Stark's conjecture may simply + be wrong.) In case of difficulties, try \tet{bnrclassfield}: + \bprog + ? bnr = bnrinit(bnfinit(y^8-12*y^6+36*y^4-36*y^2+9,1), 2); + ? bnrstark(bnr) + *** at top-level: bnrstark(bnr) + *** ^------------- + *** bnrstark: need 3919350809720744 coefficients in initzeta. + *** Computation impossible. + ? bnrclassfield(bnr) + time = 20 ms. + %2 = [x^2 + (-2/3*y^6 + 7*y^4 - 14*y^2 + 3)] + @eprog + +Function: bnrstarkunit +Class: basic +Section: number_fields +C-Name: bnrstarkunit +Prototype: GDG +Help: bnrstarkunit(bnr,{subgroup}): bnr being as output by bnrinit, returns + the characteristic polynomial of the (conjectural) Stark unit corresponding + to the module in bnr and the given congruence subgroup (the trivial subgroup + if omitted). The ground field must be totally real and all but one infinite + place must become complex in the class field. +Doc: + \var{bnr} being as output by \kbd{bnrinit}, returns the characteristic + polynomial of the (conjectural) Stark unit corresponding to the modulus in + \var{bnr} and the given congruence subgroup (as usual, omit $\var{subgroup}$ + if you want the whole ray class group). + + The ground field attached to \var{bnr} must be totally real and + all but one infinite place must become complex in the class field, which + must be a quadratic extension of its totally real subfield. Finally, + the output is given as a polynomial in $x$, so the main + variable of \var{bnr} must not be $x$. Here is an example: + \bprog + ? bnf = bnfinit(y^2 - 2); + ? bnr = bnrinit(bnf, [15, [1,0]]); + ? lift(bnrstarkunit(bnr)) + %3 = x^8 + (-9000*y - 12728)*x^7 + (57877380*y + 81850978)*x^6 + ... + 1 + @eprog + +Function: break +Class: basic +Section: programming/control +C-Name: break0 +Prototype: D1,L, +Help: break({n=1}): interrupt execution of current instruction sequence, and + exit from the n innermost enclosing loops. +Doc: interrupts execution of current \var{seq}, and + immediately exits from the $n$ innermost enclosing loops, within the + current function call (or the top level loop); the integer $n$ must be + positive. If $n$ is greater than the number of enclosing loops, all + enclosing loops are exited. + +Function: breakpoint +Class: basic +Section: programming/control +C-Name: pari_breakpoint +Prototype: v +Help: breakpoint(): interrupt the program and enter the breakloop. The program + continues when the breakloop is exited. +Doc: Interrupt the program and enter the breakloop. The program continues when + the breakloop is exited. + \bprog + ? f(N,x)=my(z=x^2+1);breakpoint();gcd(N,z^2+1-z); + ? f(221,3) + *** at top-level: f(221,3) + *** ^-------- + *** in function f: my(z=x^2+1);breakpoint();gcd(N,z + *** ^-------------------- + *** Break loop: type to continue; 'break' to go back to GP + break> z + 10 + break> + %2 = 13 + @eprog + +Function: call +Class: basic +Section: programming/specific +C-Name: call0 +Prototype: GG +Help: call(f,A): A being a vector, evaluates f(A[1],...,A[#A]). +Doc: $A=[a_{1},\dots, a_{n}]$ being a vector and $f$ being a function, + returns the evaluation of $f(a_{1},\dots,a_{n})$. + $f$ can also be the name of a built-in GP function. + If $\# A =1$, \tet{call}($f,A$) = \tet{apply}($f,A$)[1]. + If $f$ is variadic (has a variable number of arguments), then + the variadic arguments are grouped in a vector in the last component of $A$. + + This function is useful + + \item when writing a variadic function, to call another one: + \bprog + fprintf(file,format,args[..]) = write(file, call(strprintf,[format,args])) + @eprog + + \item when dealing with function arguments with unspecified arity. + + The function below implements a global memoization interface: + \bprog + memo=Map(); + memoize(f,A[..])= + { + my(res); + if(!mapisdefined(memo, [f,A], &res), + res = call(f,A); + mapput(memo,[f,A],res)); + res; + } + @eprog + for example: + \bprog + ? memoize(factor,2^128+1) + %3 = [59649589127497217,1;5704689200685129054721,1] + ? ## + *** last result computed in 76 ms. + ? memoize(factor,2^128+1) + %4 = [59649589127497217,1;5704689200685129054721,1] + ? ## + *** last result computed in 0 ms. + ? memoize(ffinit,3,3) + %5 = Mod(1,3)*x^3+Mod(1,3)*x^2+Mod(1,3)*x+Mod(2,3) + ? fibo(n)=if(n==0,0,n==1,1,memoize(fibo,n-2)+memoize(fibo,n-1)); + ? fibo(100) + %7 = 354224848179261915075 + @eprog + + \item to call operators through their internal names without using + \kbd{alias} + \bprog + matnbelts(M) = call("_*_",matsize(M)) + @eprog + +Function: ceil +Class: basic +Section: conversions +C-Name: gceil +Prototype: G +Help: ceil(x): ceiling of x = smallest integer >= x. +Description: + (small):small:parens $1 + (int):int:copy:parens $1 + (real):int ceilr($1) + (mp):int mpceil($1) + (gen):gen gceil($1) +Doc: + ceiling of $x$. When $x$ is in $\R$, the result is the + smallest integer greater than or equal to $x$. Applied to a rational + function, $\kbd{ceil}(x)$ returns the Euclidean quotient of the numerator by + the denominator. + +Function: centerlift +Class: basic +Section: conversions +C-Name: centerlift0 +Prototype: GDn +Help: centerlift(x,{v}): centered lift of x. Same as lift except for + intmod and padic components. +Description: + (pol):pol centerlift($1) + (vec):vec centerlift($1) + (gen):gen centerlift($1) + (pol, var):pol centerlift0($1, $2) + (vec, var):vec centerlift0($1, $2) + (gen, var):gen centerlift0($1, $2) +Doc: Same as \tet{lift}, except that \typ{INTMOD} and \typ{PADIC} components + are lifted using centered residues: + + \item for a \typ{INTMOD} $x\in \Z/n\Z$, the lift $y$ is such that + $-n/2y, 0 if x=y, -1 + if x$ vector $>$ scalar. + For example: + \bprog + ? cmp(1, 2) + %1 = -1 + ? cmp(2, 1) + %2 = 1 + ? cmp(1, 1.0) \\ note that 1 == 1.0, but (1===1.0) is false. + %3 = -1 + ? cmp(x + Pi, []) + %4 = -1 + @eprog\noindent This function is mostly useful to handle sorted lists or + vectors of arbitrary objects. For instance, if $v$ is a vector, the + construction \kbd{vecsort(v, cmp)} is equivalent to \kbd{Set(v)}. + +Function: component +Class: basic +Section: conversions +C-Name: compo +Prototype: GL +Help: component(x,n): the n'th component of the internal representation of + x. For vectors or matrices, it is simpler to use x[]. For list objects such + as nf, bnf, bnr or ell, it is much easier to use member functions starting + with ".". +Description: + (error,small):gen err_get_compo($1, $2) + (gen,small):gen compo($1,$2) +Doc: extracts the $n^{\text{th}}$-component of $x$. This is to be understood + as follows: every PARI type has one or two initial \idx{code words}. The + components are counted, starting at 1, after these code words. In particular + if $x$ is a vector, this is indeed the $n^{\text{th}}$-component of $x$, if + $x$ is a matrix, the $n^{\text{th}}$ column, if $x$ is a polynomial, the + $n^{\text{th}}$ coefficient (i.e.~of degree $n-1$), and for power series, + the $n^{\text{th}}$ significant coefficient. + + For polynomials and power series, one should rather use \tet{polcoef}, and + for vectors and matrices, the \kbd{[$\,$]} operator. Namely, if $x$ is a + vector, then \tet{x[n]} represents the $n^{\text{th}}$ component of $x$. If + $x$ is a matrix, \tet{x[m,n]} represents the coefficient of row \kbd{m} and + column \kbd{n} of the matrix, \tet{x[m,]} represents the $m^{\text{th}}$ + \emph{row} of $x$, and \tet{x[,n]} represents the $n^{\text{th}}$ + \emph{column} of $x$. + + Using of this function requires detailed knowledge of the structure of the + different PARI types, and thus it should almost never be used directly. + Some useful exceptions: + \bprog + ? x = 3 + O(3^5); + ? component(x, 2) + %2 = 81 \\ p^(p-adic accuracy) + ? component(x, 1) + %3 = 3 \\ p + ? q = Qfb(1,2,3); + ? component(q, 1) + %5 = 1 + @eprog + +Function: concat +Class: basic +Section: linear_algebra +C-Name: gconcat +Prototype: GDG +Help: concat(x,{y}): concatenation of x and y, which can be scalars, vectors + or matrices, or lists (in this last case, both x and y have to be lists). If + y is omitted, x has to be a list or row vector and its elements are + concatenated. +Description: + (vecvecsmall,vecvecsmall):vecvecsmall gconcat($1, $2) + (vecvecsmall):vecsmall gconcat1($1) + (mp,mp):vec gconcat($1, $2) + (vec,mp):vec gconcat($1, $2) + (mp,vec):vec gconcat($1, $2) + (vec,vec):vec gconcat($1, $2) + (list,list):list gconcat($1, $2) + (genstr,gen):genstr gconcat($1, $2) + (gen,genstr):genstr gconcat($1, $2) + (gen):gen gconcat1($1) + (gen,):gen gconcat1($1) + (gen,gen):gen gconcat($1, $2) +Doc: concatenation of $x$ and $y$. If $x$ or $y$ is + not a vector or matrix, it is considered as a one-dimensional vector. All + types are allowed for $x$ and $y$, but the sizes must be compatible. Note + that matrices are concatenated horizontally, i.e.~the number of rows stays + the same. Using transpositions, one can concatenate them vertically, + but it is often simpler to use \tet{matconcat}. + \bprog + ? x = matid(2); y = 2*matid(2); + ? concat(x,y) + %2 = + [1 0 2 0] + + [0 1 0 2] + ? concat(x~,y~)~ + %3 = + [1 0] + + [0 1] + + [2 0] + + [0 2] + ? matconcat([x;y]) + %4 = + [1 0] + + [0 1] + + [2 0] + + [0 2] + @eprog\noindent + To concatenate vectors sideways (i.e.~to obtain a two-row or two-column + matrix), use \tet{Mat} instead, or \tet{matconcat}: + \bprog + ? x = [1,2]; + ? y = [3,4]; + ? concat(x,y) + %3 = [1, 2, 3, 4] + + ? Mat([x,y]~) + %4 = + [1 2] + + [3 4] + ? matconcat([x;y]) + %5 = + [1 2] + + [3 4] + @eprog + Concatenating a row vector to a matrix having the same number of columns will + add the row to the matrix (top row if the vector is $x$, i.e.~comes first, and + bottom row otherwise). + + The empty matrix \kbd{[;]} is considered to have a number of rows compatible + with any operation, in particular concatenation. (Note that this is + \emph{not} the case for empty vectors \kbd{[~]} or \kbd{[~]\til}.) + + If $y$ is omitted, $x$ has to be a row vector or a list, in which case its + elements are concatenated, from left to right, using the above rules. + \bprog + ? concat([1,2], [3,4]) + %1 = [1, 2, 3, 4] + ? a = [[1,2]~, [3,4]~]; concat(a) + %2 = + [1 3] + + [2 4] + + ? concat([1,2; 3,4], [5,6]~) + %3 = + [1 2 5] + + [3 4 6] + ? concat([%, [7,8]~, [1,2,3,4]]) + %5 = + [1 2 5 7] + + [3 4 6 8] + + [1 2 3 4] + @eprog +Variant: \fun{GEN}{gconcat1}{GEN x} is a shortcut for \kbd{gconcat(x,NULL)}. + +Function: conj +Class: basic +Section: conversions +C-Name: gconj +Prototype: G +Help: conj(x): the algebraic conjugate of x. +Doc: + conjugate of $x$. The meaning of this + is clear, except that for real quadratic numbers, it means conjugation in the + real quadratic field. This function has no effect on integers, reals, + intmods, fractions or $p$-adics. The only forbidden type is polmod + (see \kbd{conjvec} for this). + +Function: conjvec +Class: basic +Section: conversions +C-Name: conjvec +Prototype: Gp +Help: conjvec(z): conjugate vector of the algebraic number z. +Doc: + conjugate vector representation of $z$. If $z$ is a + polmod, equal to \kbd{Mod}$(a,T)$, this gives a vector of length + $\text{degree}(T)$ containing: + + \item the complex embeddings of $z$ if $T$ has rational coefficients, + i.e.~the $a(r[i])$ where $r = \kbd{polroots}(T)$; + + \item the conjugates of $z$ if $T$ has some intmod coefficients; + + \noindent if $z$ is a finite field element, the result is the vector of + conjugates $[z,z^{p},z^{p^{2}},\ldots,z^{p^{n-1}}]$ where $n=\text{degree}(T)$. + + \noindent If $z$ is an integer or a rational number, the result is~$z$. If + $z$ is a (row or column) vector, the result is a matrix whose columns are + the conjugate vectors of the individual elements of $z$. + +Function: content +Class: basic +Section: number_theoretical +C-Name: content0 +Prototype: GDG +Help: content(x,{D}): gcd of all the components of x, when this makes sense. +Doc: computes the gcd of all the coefficients of $x$, + when this gcd makes sense. This is the natural definition + if $x$ is a polynomial (and by extension a power series) or a + vector/matrix. This is in general a weaker notion than the \emph{ideal} + generated by the coefficients: + \bprog + ? content(2*x+y) + %1 = 1 \\ = gcd(2,y) over Q[y] + @eprog + + If $x$ is a scalar, this simply returns the absolute value of $x$ if $x$ is + rational (\typ{INT} or \typ{FRAC}), and either $1$ (inexact input) or $x$ + (exact input) otherwise; the result should be identical to \kbd{gcd(x, 0)}. + + The content of a rational function is the ratio of the contents of the + numerator and the denominator. In recursive structures, if a + matrix or vector \emph{coefficient} $x$ appears, the gcd is taken + not with $x$, but with its content: + \bprog + ? content([ [2], 4*matid(3) ]) + %1 = 2 + @eprog\noindent The content of a \typ{VECSMALL} is computed assuming the + entries are signed integers. + + The optional argument $D$ allows to control over which ring we compute + and get a more predictable behaviour: + + \item $1$: we only consider the underlying $\Q$-structure and the + denominator is a (positive) rational number + + \item a simple variable, say \kbd{'x}: all entries are considered as + rational functions in $K(x)$ for some field $K$ and the content is an + element of $K$. + + \bprog + ? f = x + 1/y + 1/2; + ? content(f) \\ as a t_POL in x + %2 = 1/(2*y) + ? content(f, 1) \\ Q-content + %3 = 1/2 + ? content(f, y) \\ as a rational function in y + %4 = 1/2 + ? g = x^2*y + y^2*x; + ? content(g, x) + %6 = y + ? content(g, y) + %7 = x + @eprog + +Function: contfrac +Class: basic +Section: number_theoretical +C-Name: contfrac0 +Prototype: GDGD0,L, +Help: contfrac(x,{b},{nmax}): continued fraction expansion of x (x + rational,real or rational function). b and nmax are both optional, where b + is the vector of numerators of the continued fraction, and nmax is a bound + for the number of terms in the continued fraction expansion. +Doc: returns the row vector whose components are the partial quotients of the + \idx{continued fraction} expansion of $x$. In other words, a result + $[a_{0},\dots,a_{n}]$ means that $x \approx a_{0}+1/(a_{1}+\dots+1/a_{n})$. The + output is normalized so that $a_{n} \neq 1$ (unless we also have $n = 0$). + + The number of partial quotients $n+1$ is limited by \kbd{nmax}. If + \kbd{nmax} is omitted, the expansion stops at the last significant partial + quotient. + \bprog + ? \p19 + realprecision = 19 significant digits + ? contfrac(Pi) + %1 = [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2] + ? contfrac(Pi,, 3) \\ n = 2 + %2 = [3, 7, 15] + @eprog\noindent + $x$ can also be a rational function or a power series. + + If a vector $b$ is supplied, the numerators are equal to the coefficients + of $b$, instead of all equal to $1$ as above; more precisely, $x \approx + (1/b_{0})(a_{0}+b_{1}/(a_{1}+\dots+b_{n}/a_{n}))$; for a numerical continued + fraction ($x$ real), the $a_{i}$ are integers, as large as possible; + if $x$ is a + rational function, they are polynomials with $\deg a_{i} = \deg b_{i} + 1$. + The length of the result is then equal to the length of $b$, unless the next + partial quotient cannot be reliably computed, in which case the expansion + stops. This happens when a partial remainder is equal to zero (or too small + compared to the available significant digits for $x$ a \typ{REAL}). + + A direct implementation of the numerical continued fraction + \kbd{contfrac(x,b)} described above would be + \bprog + \\ "greedy" generalized continued fraction + cf(x, b) = + { my( a= vector(#b), t ); + + x *= b[1]; + for (i = 1, #b, + a[i] = floor(x); + t = x - a[i]; if (!t || i == #b, break); + x = b[i+1] / t; + ); a; + } + @eprog\noindent There is some degree of freedom when choosing the $a_{i}$; the + program above can easily be modified to derive variants of the standard + algorithm. In the same vein, although no builtin + function implements the related \idx{Engel expansion} (a special kind of + \idx{Egyptian fraction} decomposition: $x = 1/a_{1} + 1/(a_{1}a_{2}) + \dots$), + it can be obtained as follows: + \bprog + \\ n terms of the Engel expansion of x + engel(x, n = 10) = + { my( u = x, a = vector(n) ); + for (k = 1, n, + a[k] = ceil(1/u); + u = u*a[k] - 1; + if (!u, break); + ); a + } + @eprog + + \misctitle{Obsolete hack} (don't use this): if $b$ is an integer, \var{nmax} + is ignored and the command is understood as \kbd{contfrac($x,, b$)}. +Variant: Also available are \fun{GEN}{gboundcf}{GEN x, long nmax}, + \fun{GEN}{gcf}{GEN x} and \fun{GEN}{gcf2}{GEN b, GEN x}. + +Function: contfraceval +Class: basic +Section: sums +C-Name: contfraceval +Prototype: GGD-1,L, +Help: contfraceval(CF,t,{lim=-1}): given a continued fraction CF from + contfracinit, evaluate the first lim terms of the continued fraction at t + (all terms if lim is negative or omitted). +Doc: Given a continued fraction \kbd{CF} output by \kbd{contfracinit}, evaluate + the first \kbd{lim} terms of the continued fraction at \kbd{t} (all + terms if \kbd{lim} is negative or omitted; if positive, \kbd{lim} must be + less than or equal to the length of \kbd{CF}. + +Function: contfracinit +Class: basic +Section: sums +C-Name: contfracinit +Prototype: GD-1,L, +Help: contfracinit(M,{lim = -1}): given M representing the power + series S = sum_{n>=0} M[n+1]z^n, transform it into a continued fraction + suitable for evaluation. +Doc: Given $M$ representing the power series $S=\sum_{n\ge0} M[n+1]z^{n}$, + transform it into a continued fraction in Euler form, using the + quotient-difference algorithm; restrict to + $n\leq \kbd{lim}$ if latter is nonnegative. $M$ can be a vector, a power + series, a polynomial; if the limiting parameter \kbd{lim} is present, a + rational function is also allowed (and converted to a power series of that + accuracy). + + The result is a 2-component vector $[A,B]$ such that + $S = M[1] / (1+A[1]z+B[1]z^{2}/(1+A[2]z+B[2]z^{2}/(1+\dots 1/(1+A[lim/2]z))))$. + Does not work if any coefficient of $M$ vanishes, nor for series for + which certain partial denominators vanish. +Variant: Also available is + \fun{GEN}{quodif}{GEN M, long n} + which returns the standard continued fraction, as a vector $C$ such that + $S = c[1] / (1 + c[2]z / (1+c[3]z/(1+\dots...c[lim]z)))$. + +Function: contfracpnqn +Class: basic +Section: number_theoretical +C-Name: contfracpnqn +Prototype: GD-1,L, +Help: contfracpnqn(x,{n=-1}): [p_n,p_{n-1}; q_n,q_{n-1}] corresponding to the + continued fraction x. If n >= 0 is present, returns all convergents from + p_0/q_0 up to p_n/q_n. +Doc: when $x$ is a vector or a one-row matrix, $x$ + is considered as the list of partial quotients $[a_{0},a_{1},\dots,a_{n}]$ of a + rational number, and the result is the 2 by 2 matrix + $[p_{n},p_{n-1};q_{n},q_{n-1}]$ in the standard notation of continued fractions, + so $p_{n}/q_{n}=a_{0}+1/(a_{1}+\dots+1/a_{n})$. If $x$ is a matrix with two rows + $[b_{0},b_{1},\dots,b_{n}]$ and $[a_{0},a_{1},\dots,a_{n}]$, this is then considered as a + generalized continued fraction and we have similarly + $p_{n}/q_{n}=(1/b_{0})(a_{0}+b_{1}/(a_{1}+\dots+b_{n}/a_{n}))$. Note that in this case one + usually has $b_{0}=1$. + + If $n \geq 0$ is present, returns all convergents from $p_{0}/q_{0}$ up to + $p_{n}/q_{n}$. (All convergents if $x$ is too small to compute the $n+1$ + requested convergents.) + \bprog + ? a = contfrac(Pi,10) + %1 = [3, 7, 15, 1, 292, 1, 1, 1, 3] + ? allpnqn(x) = contfracpnqn(x,#x) \\ all convergents + ? allpnqn(a) + %3 = + [3 22 333 355 103993 104348 208341 312689 1146408] + + [1 7 106 113 33102 33215 66317 99532 364913] + ? contfracpnqn(a) \\ last two convergents + %4 = + [1146408 312689] + + [ 364913 99532] + + ? contfracpnqn(a,3) \\ first three convergents + %5 = + [3 22 333 355] + + [1 7 106 113] + @eprog +Variant: also available is \fun{GEN}{pnqn}{GEN x} for $n = -1$. + +Function: copy +Class: gp2c +Description: + (small):small:parens $1 + (int):int icopy($1) + (real):real gcopy($1) + (mp):mp gcopy($1) + (vecsmall):vecsmall gcopy($1) + (vec):vec gcopy($1) + (pol):pol gcopy($1) + (list):list listinit($1) + (gen):gen gcopy($1) + +Function: core +Class: basic +Section: number_theoretical +C-Name: core0 +Prototype: GD0,L, +Help: core(n,{flag=0}): unique squarefree integer d + dividing n such that n/d is a square. If (optional) flag is nonzero, output + the two-component row vector [d,f], where d is the unique squarefree integer + dividing n such that n/d=f^2 is a square. +Doc: if $n$ is an integer written as + $n=df^{2}$ with $d$ squarefree, returns $d$. If $\fl$ is nonzero, + returns the two-element row vector $[d,f]$. By convention, we write $0 = 0 + \times 1^{2}$, so \kbd{core(0, 1)} returns $[0,1]$. +Variant: Also available are \fun{GEN}{core}{GEN n} ($\fl = 0$) and + \fun{GEN}{core2}{GEN n} ($\fl = 1$) + +Function: coredisc +Class: basic +Section: number_theoretical +C-Name: coredisc0 +Prototype: GD0,L, +Help: coredisc(n,{flag=0}): discriminant of the quadratic field Q(sqrt(n)). + If (optional) flag is nonzero, output a two-component row vector [d,f], + where d is the discriminant of the quadratic field Q(sqrt(n)) and n=df^2. f + may be a half integer. +Doc: a \emph{fundamental discriminant} is an integer of the form $t\equiv 1 + \mod 4$ or $4t \equiv 8,12 \mod 16$, with $t$ squarefree (i.e.~$1$ or the + discriminant of a quadratic number field). Given a nonzero integer + $n$, this routine returns the (unique) fundamental discriminant $d$ + such that $n=df^{2}$, $f$ a positive rational number. If $\fl$ is nonzero, + returns the two-element row vector $[d,f]$. If $n$ is congruent to + 0 or 1 modulo 4, $f$ is an integer, and a half-integer otherwise. + + By convention, \kbd{coredisc(0, 1))} returns $[0,1]$. + + Note that \tet{quaddisc}$(n)$ returns the same value as \kbd{coredisc}$(n)$, + and also works with rational inputs $n\in\Q^{*}$. +Variant: Also available are \fun{GEN}{coredisc}{GEN n} ($\fl = 0$) and + \fun{GEN}{coredisc2}{GEN n} ($\fl = 1$) + +Function: cos +Class: basic +Section: transcendental +C-Name: gcos +Prototype: Gp +Help: cos(x): cosine of x. +Description: + (real):real mpcos($1) + (mp):real:prec gcos($1, $prec) + (gen):gen:prec gcos($1, $prec) +Doc: cosine of $x$. + Note that, for real $x$, cosine and sine can be obtained simultaneously as + \bprog + cs(x) = my(z = exp(I*x)); [real(z), imag(z)]; + @eprog and for general complex $x$ as + \bprog + cs2(x) = my(z = exp(I*x), u = 1/z); [(z+u)/2, (z-u)/2]; + @eprog Note that the latter function suffers from catastrophic cancellation + when $z^{2} \approx \pm1$. + +Function: cosh +Class: basic +Section: transcendental +C-Name: gcosh +Prototype: Gp +Help: cosh(x): hyperbolic cosine of x. +Description: + (mp):real:prec gcosh($1, $prec) + (gen):gen:prec gcosh($1, $prec) +Doc: hyperbolic cosine of $x$. + +Function: cotan +Class: basic +Section: transcendental +C-Name: gcotan +Prototype: Gp +Help: cotan(x): cotangent of x. +Description: + (mp):real:prec gcotan($1, $prec) + (gen):gen:prec gcotan($1, $prec) +Doc: cotangent of $x$. + +Function: cotanh +Class: basic +Section: transcendental +C-Name: gcotanh +Prototype: Gp +Help: cotanh(x): hyperbolic cotangent of x. +Description: + (mp):real:prec gcotanh($1, $prec) + (gen):gen:prec gcotanh($1, $prec) +Doc: hyperbolic cotangent of $x$. + +Function: dbg_down +Class: gp +Section: programming/control +C-Name: dbg_down +Prototype: vD1,L, +Help: dbg_down({n=1}): (break loop) go down n frames. Cancel a previous dbg_up. +Doc: (In the break loop) go down $n$ frames. This allows to cancel a previous + call to \kbd{dbg\_up}. + \bprog + ? x = 0; + ? g(x) = x-3; + ? f(x) = 1 / g(x+1); + ? for (x = 1, 5, f(x+1)) + *** at top-level: for(x=1,5,f(x+1)) + *** ^------- + *** in function f: 1/g(x+1) + *** ^------- + *** _/_: impossible inverse in gdiv: 0. + *** Break loop: type 'break' to go back to GP prompt + break> dbg_up(3) \\ go up 3 frames + *** at top-level: for(x=1,5,f(x+1)) + *** ^----------------- + break> x + 0 + break> dbg_down() + *** at top-level: for(x=1,5,f(x+1)) + *** ^------- + break> x + 1 + break> dbg_down() + *** at top-level: for(x=1,5,f(x+1)) + *** ^------- + break> x + 1 + break> dbg_down() + *** at top-level: for(x=1,5,f(x+1)) + *** ^------- + *** in function f: 1/g(x+1) + *** ^------- + break> x + 2 + @eprog\noindent The above example shows that the notion of GP frame is + finer than the usual stack of function calls (as given for instance by the + GDB \kbd{backtrace} command): GP frames are attached to variable scopes + and there are frames attached to control flow instructions such as a + \kbd{for} loop above. + +Function: dbg_err +Class: gp +Section: programming/control +C-Name: dbg_err +Prototype: +Help: dbg_err(): (break loop) return the error data of the current error, if any. +Doc: In the break loop, return the error data of the current error, if any. + See \tet{iferr} for details about error data. Compare: + \bprog + ? iferr(1/(Mod(2,12019)^(6!)-1),E,Vec(E)) + %1 = ["e_INV", "Fp_inv", Mod(119, 12019)] + ? 1/(Mod(2,12019)^(6!)-1) + *** at top-level: 1/(Mod(2,12019)^(6!)- + *** ^-------------------- + *** _/_: impossible inverse in Fp_inv: Mod(119, 12019). + *** Break loop: type 'break' to go back to GP prompt + break> Vec(dbg_err()) + ["e_INV", "Fp_inv", Mod(119, 12019)] + @eprog + +Function: dbg_up +Class: gp +Section: programming/control +C-Name: dbg_up +Prototype: vD1,L, +Help: dbg_up({n=1}): (break loop) go up n frames, which allows to inspect data + of the parent function. +Doc: (In the break loop) go up $n$ frames, which allows to inspect data of the + parent function. To cancel a \tet{dbg_up} call, use \tet{dbg_down}. + \bprog + ? x = 0; + ? g(x) = x-3; + ? f(x) = 1 / g(x+1); + ? for (x = 1, 5, f(x+1)) + *** at top-level: for(x=1,5,f(x+1)) + *** ^------- + *** in function f: 1/g(x+1) + *** ^------- + *** _/_: impossible inverse in gdiv: 0. + *** Break loop: type 'break' to go back to GP prompt + break> x + 2 + break> dbg_up() + *** at top-level: for(x=1,5,f(x+1)) + *** ^------- + break> x + 1 + break> dbg_up() + *** at top-level: for(x=1,5,f(x+1)) + *** ^------- + break> x + 1 + break> dbg_up() + *** at top-level: for(x=1,5,f(x+1)) + *** ^----------------- + break> x + 0 + break> dbg_down() \\ back up once + *** at top-level: for(x=1,5,f(x+1)) + *** ^------- + break> x + 1 + @eprog\noindent The above example shows that the notion of GP frame is + finer than the usual stack of function calls (as given for instance by the + GDB \kbd{backtrace} command): GP frames are attached to variable scopes + and there are frames attached to control flow instructions such as a + \kbd{for} loop above. + +Function: dbg_x +Class: basic +Section: programming/control +C-Name: dbgGEN +Prototype: vGD-1,L, +Help: dbg_x(A,{n}): print inner structure of A, complete if n is omitted, up to + level n otherwise. Intended for debugging. +Doc: Print the inner structure of $A$, complete if $n$ is omitted, up + to level $n$ otherwise. This function is useful for debugging. It is similar + to \b{x} but does not require $A$ to be a history entry. In particular, + it can be used in the break loop. + +Function: default +Class: basic +Section: programming/specific +C-Name: default0 +Prototype: DrDs +Help: default({key},{val}): returns the current value of the + default key. If val is present, set opt to val first. If no argument is + given, print a list of all defaults as well as their values. +Description: + ("realprecision"):small:prec getrealprecision() + ("realprecision",small):small:prec setrealprecision($2, &$prec) + ("seriesprecision"):small precdl + ("seriesprecision",small):small:parens precdl = $2 + ("debug"):small DEBUGLEVEL + ("debug",small):small:parens DEBUGLEVEL = $2 + ("debugmem"):small DEBUGMEM + ("debugmem",small):small:parens DEBUGMEM = $2 + ("debugfiles"):small DEBUGFILES + ("debugfiles",small):small:parens DEBUGFILES = $2 + ("factor_add_primes"):small factor_add_primes + ("factor_add_primes",small):small factor_add_primes = $2 + ("factor_proven"):small factor_proven + ("factor_proven",small):small factor_proven = $2 + ("new_galois_format"):small new_galois_format + ("new_galois_format",small):small new_galois_format = $2 +Doc: returns the default corresponding to keyword \var{key}. If \var{val} is + present, sets the default to \var{val} first (which is subject to string + expansion first). Typing \kbd{default()} (or \b{d}) yields the complete + default list as well as their current values. See \secref{se:defaults} for an + introduction to GP defaults, \secref{se:gp_defaults} for a + list of available defaults, and \secref{se:meta} for some shortcut + alternatives. Note that the shortcuts are meant for interactive use and + usually display more information than \kbd{default}. + +Function: denominator +Class: basic +Section: conversions +C-Name: denominator +Prototype: GDG +Help: denominator(f,{D}): denominator of f. +Doc: + denominator of $f$. The meaning of this is clear when $f$ is a rational number + or function. If $f$ is an integer or a polynomial, it is treated as a rational + number or function, respectively, and the result is equal to $1$. For + polynomials, you probably want to use + \bprog + denominator( content(f) ) + @eprog\noindent instead. As for modular objects, \typ{INTMOD} and \typ{PADIC} + have denominator $1$, and the denominator of a \typ{POLMOD} is the + denominator of its lift. + + If $f$ is a recursive structure, for instance a vector or matrix, the lcm + of the denominators of its components (a common denominator) is computed. + This also applies for \typ{COMPLEX}s and \typ{QUAD}s. + + \misctitle{Warning} Multivariate objects are created according to variable + priorities, with possibly surprising side effects ($x/y$ is a polynomial, but + $y/x$ is a rational function). See \secref{se:priority}. + + The optional argument $D$ allows to control over which ring we compute the + denominator and get a more predictable behaviour: + + \item $1$: we only consider the underlying $\Q$-structure and the + denominator is a (positive) rational integer + + \item a simple variable, say \kbd{'x}: all entries as rational functions + in $K(x)$ and the denominator is a polynomial in $x$. + + \bprog + ? f = x + 1/y + 1/2; + ? denominator(f) \\ a t_POL in x + %2 = 1 + ? denominator(f, 1) \\ Q-denominator + %3 = 2 + ? denominator(f, x) \\ as a t_POL in x, seen above + %4 = 1 + ? denominator(f, y) \\ as a rational function in y + %5 = 2*y + @eprog +Variant: Also available are + \fun{GEN}{denom}{GEN x} which implements the not very useful default + behaviour ($D$ is \kbd{NULL}) and \fun{GEN}{Q_denom}{GEN x} ($D = 1$). + +Function: deriv +Class: basic +Section: polynomials +C-Name: deriv +Prototype: GDn +Help: deriv(x,{v}): derivative of x with respect to v, or to the main + variable of x if v is omitted. +Doc: derivative of $x$ with respect to the main + variable if $v$ is omitted, and with respect to $v$ otherwise. The derivative + of a scalar type is zero, and the derivative of a vector or matrix is done + componentwise. One can use $x'$ as a shortcut if the derivative is with + respect to the main variable of $x$; and also use $x''$, etc., for multiple + derivatives altough \kbd{derivn} is often preferrable. + + By definition, the main variable of a \typ{POLMOD} is the main variable among + the coefficients from its two polynomial components (representative and + modulus); in other words, assuming a polmod represents an element of + $R[X]/(T(X))$, the variable $X$ is a mute variable and the derivative is + taken with respect to the main variable used in the base ring $R$. + + \bprog + ? f = (x/y)^5; + ? deriv(f) + %2 = 5/y^5*x^4 + ? f' + %3 = 5/y^5*x^4 + ? deriv(f, 'x) \\ same since 'x is the main variable + %4 = 5/y^5*x^4 + ? deriv(f, 'y) + %5 = -5/y^6*x^5 + @eprog + + This function also operates on closures, in which case the variable + must be omitted. It returns a closure performing a numerical + differentiation as per \kbd{derivnum}: + \bprog + ? f(x) = x^2; + ? g = deriv(f) + ? g(1) + %3 = 2.0000000000000000000000000000000000000 + ? f(x) = sin(exp(x)); + ? deriv(f)(0) + %5 = 0.54030230586813971740093660744297660373 + ? cos(1) + %6 = 0.54030230586813971740093660744297660373 + @eprog + +Function: derivn +Class: basic +Section: polynomials +C-Name: derivn +Prototype: GLDn +Help: derivn(x,n,{v}): n-th derivative of x with respect to v, or to the main + variable of x if v is omitted. +Doc: + $n$-th derivative of $x$ with respect to the main + variable if $v$ is omitted, and with respect to $v$ otherwise; the integer + $n$ must be nonnegative. The derivative + of a scalar type is zero, and the derivative of a vector or matrix is done + componentwise. One can use $x'$, $x''$, etc., as a shortcut if the + derivative is with respect to the main variable of $x$. + + By definition, the main variable of a \typ{POLMOD} is the main variable among + the coefficients from its two polynomial components (representative and + modulus); in other words, assuming a polmod represents an element of + $R[X]/(T(X))$, the variable $X$ is a mute variable and the derivative is + taken with respect to the main variable used in the base ring $R$. + + \bprog + ? f = (x/y)^5; + ? derivn(f, 2) + %2 = 20/y^5*x^3 + ? f'' + %3 = 20/y^5*x^3 + ? derivn(f, 2, 'x) \\ same since 'x is the main variable + %4 = 20/y^5*x^3 + ? derivn(f, 2, 'y) + %5 = 30/y^7*x^5 + @eprog + + This function also operates on closures, in which case the variable + must be omitted. It returns a closure performing a numerical + differentiation as per \kbd{derivnum}: + \bprog + ? f(x) = x^10; + ? g = derivn(f, 5) + ? g(1) + %3 = 30240.000000000000000000000000000000000 + + ? derivn(zeta, 2)(0) + %4 = -2.0063564559085848512101000267299604382 + ? zeta''(0) + %5 = -2.0063564559085848512101000267299604382 + @eprog + +Function: derivnum +Class: basic +Section: sums +C-Name: derivnum0 +Prototype: V=GEDGp +Help: derivnum(X=a,expr,{ind=1}): numerical derivation of expr with respect to + X at X = a. The order of derivation is given by parameter 'ind', which can + be a vector. +Wrapper: (,Gp) +Description: + (gen,gen):gen:prec derivnum(${2 cookie}, ${2 wrapper}, $1, $prec) + (gen,gen,gen):gen:prec derivfunk(${2 cookie}, ${2 wrapper}, $1, $3, $prec) +Doc: numerical derivation of \var{expr} with respect to $X$ at $X=a$. The + order of derivation is 1 by default. + + \bprog + ? derivnum(x=0, sin(exp(x))) - cos(1) + %1 = 0.E-38 + @eprog + A clumsier approach, which would not work in library mode, is + \bprog + ? f(x) = sin(exp(x)) + ? f'(0) - cos(1) + %2 = 0.E-38 + @eprog + + \item When $a$ is a numerical type (integer, rational number, real number or + \typ{COMPLEX} of such), performs numerical derivation. + + \item When $a$ is a (polynomial, rational function or) power series, compute + \kbd{derivnum(t=a,f)} as $f'(a) = (f(a))'/a'$: + \bprog + ? derivnum(x = 1 + t, sqrt(x)) + %1 = 1/2 - 1/4*t + 3/16*t^2 - 5/32*t^3 + ... + O(t^16) + ? derivnum(x = 1/(1 + t), sqrt(x)) + %2 = 1/2 + 1/4*t - 1/16*t^2 + 1/32*t^3 + ... + O(t^16) + ? derivnum(x = 1 + t + O(t^17), sqrt(x)) + %3 = 1/2 - 1/4*t + 3/16*t^2 - 5/32*t^3 + ... + O(t^16) + @eprog + + If the parameter \var{ind} is present, it can be + + \item a nonnegative integer $m$, in which case we return $f^{(m)}(x)$; + + \item or a vector of orders, in which case we return the vector of + derivatives. + + \bprog + ? derivnum(x = 0, exp(sin(x)), 16) \\ 16-th derivative + %1 = -52635599.000000000000000000000000000000 + + ? round( derivnum(x = 0, exp(sin(x)), [0..13]) ) \\ 0-13-th derivatives + %2 = [1, 1, 1, 0, -3, -8, -3, 56, 217, 64, -2951, -12672, 5973, 309376] + @eprog + + \synt{derivfunk}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN ind, long prec}. + Also available is + \fun{GEN}{derivfun}{void *E, GEN (*eval)(void *, GEN), GEN a, long prec}. + If $a$ is a numerical type (\typ{INT}, \typ{FRAC}, \typ{REAL} or + \typ{COMPLEX} of such, we have + \fun{GEN}{derivnumk}{void *E, GEN (*eval)(void *, GEN, long), GEN a, GEN ind, long prec} + and + \fun{GEN}{derivnum}{void *E, GEN (*eval)(void *, GEN, long prec), GEN a, long prec} + +Function: diffop +Class: basic +Section: polynomials +C-Name: diffop0 +Prototype: GGGD1,L, +Help: diffop(x,v,d,{n=1}): apply the differential operator D to x, where D is defined + by D(v[i])=d[i], where v is a vector of variable names. D is 0 for variables + outside of v unless they appear as modulus of a POLMOD. If the optional parameter n + is given, return D^n(x) instead. +Description: + (gen,gen,gen,?1):gen diffop($1, $2, $3) + (gen,gen,gen,small):gen diffop0($1, $2, $3, $4) +Doc: + Let $v$ be a vector of variables, and $d$ a vector of the same length, + return the image of $x$ by the $n$-power ($1$ if n is not given) of the + differential operator $D$ that assumes the value \kbd{d[i]} on the variable + \kbd{v[i]}. The value of $D$ on a scalar type is zero, and $D$ applies + componentwise to a vector or matrix. When applied to a \typ{POLMOD}, if no + value is provided for the variable of the modulus, such value is derived + using the implicit function theorem. + + \misctitle{Examples} + This function can be used to differentiate formal expressions: + if $E=\exp(X^{2})$ then we have $E'=2*X*E$. We derivate $X*exp(X^{2})$ + as follows: + \bprog + ? diffop(E*X,[X,E],[1,2*X*E]) + %1 = (2*X^2 + 1)*E + @eprog + Let \kbd{Sin} and \kbd{Cos} be two function such that + $\kbd{Sin}^{2}+\kbd{Cos}^{2}=1$ and $\kbd{Cos}'=-\kbd{Sin}$. + We can differentiate $\kbd{Sin}/\kbd{Cos}$ as follows, + PARI inferring the value of $\kbd{Sin}'$ from the equation: + \bprog + ? diffop(Mod('Sin/'Cos,'Sin^2+'Cos^2-1),['Cos],[-'Sin]) + %1 = Mod(1/Cos^2, Sin^2 + (Cos^2 - 1)) + @eprog + Compute the Bell polynomials (both complete and partial) via the Faa di Bruno + formula: + \bprog + Bell(k,n=-1)= + { my(x, v, dv, var = i->eval(Str("X",i))); + + v = vector(k, i, if (i==1, 'E, var(i-1))); + dv = vector(k, i, if (i==1, 'X*var(1)*'E, var(i))); + x = diffop('E,v,dv,k) / 'E; + if (n < 0, subst(x,'X,1), polcoef(x,n,'X)); + } + @eprog +Variant: + For $n=1$, the function \fun{GEN}{diffop}{GEN x, GEN v, GEN d} is also + available. + +Function: digits +Class: basic +Section: conversions +C-Name: digits +Prototype: GDG +Help: digits(x,{b}): gives the vector formed by the digits of x in base b. +Doc: + outputs the vector of the digits of $x$ in base $b$, where $x$ and $b$ are + integers ($b = 10$ by default), from most significant down to least + significant, the digits being the the integers $0$, $1$, \dots $|b|-1$. + If $b>0$ and $x<0$, return the digits of $|x|$. + + For $x\ge1$ and $b>0$, the number of digits is + $\kbd{logint}(x,b) + 1$. See \kbd{fromdigits} for the reverse operation. + + We also allow $x$ an integral $p$-adic in which case $b$ should be omitted + or equal to $p$. Digits are still ordered from most significant to least + significant in the $p$-adic sense (meaning we start from $x$ mod $p$); + trailing zeros are truncated. + \bprog + ? digits(1230) + %1 = [1, 2, 3, 0] + + ? digits(10, 2) \\ base 2 + %2 = [1, 0, 1, 0] + @eprog\noindent By convention, $0$ has no digits: + \bprog + ? digits(0) + %3 = [] + ? digits(10,-2) \\ base -2 + %4 = [1, 1, 1, 1, 0] \\ 10 = -2 + 4 - 8 + 16 + ? 1105 + O(5^5) + %5 = 5 + 4*5^2 + 3*5^3 + O(5^5) + ? digits(%) + %6 = [0, 1, 4, 3] + @eprog + +Function: dilog +Class: basic +Section: transcendental +C-Name: dilog +Prototype: Gp +Help: dilog(x): dilogarithm of x. +Doc: principal branch of the dilogarithm of $x$, + i.e.~analytic continuation of the power series + $\text{Li}_{2}(x)=\sum_{n\ge1}x^{n}/n^{2}$. + +Function: dirdiv +Class: basic +Section: number_theoretical +C-Name: dirdiv +Prototype: GG +Help: dirdiv(x,y): division of the Dirichlet series x by the Dirichlet + series y. +Doc: $x$ and $y$ being vectors of perhaps different + lengths but with $y[1]\neq 0$ considered as \idx{Dirichlet series}, computes + the quotient of $x$ by $y$, again as a vector. + +Function: direuler +Class: basic +Section: number_theoretical +C-Name: direuler0 +Prototype: V=GGEDG +Help: direuler(p=a,b,expr,{c}): Dirichlet Euler product of expression expr + from p=a to p=b, limited to b terms. Expr should be a polynomial or rational + function in p and X, and X is understood to mean p^(-s). If c is present, + output only the first c terms. +Wrapper: (,,G) +Description: + (gen,gen,closure,?gen):gen direuler(${3 cookie}, ${3 wrapper}, $1, $2, $4) +Doc: computes the \idx{Dirichlet series} attached to the + \idx{Euler product} of expression \var{expr} as $p$ ranges through the primes + from $a$ + to $b$. \var{expr} must be a polynomial or rational function in another + variable than $p$ (say $X$) and $\var{expr}(X)$ is understood as the local + factor $\var{expr}(p^{-s})$. + + The series is output as a vector of coefficients. If $c$ is omitted, output + the first $b$ coefficients of the series; otherwise, output the first $c$ + coefficients. The following command computes the \teb{sigma} function, + attached to $\zeta(s)\zeta(s-1)$: + \bprog + ? direuler(p=2, 10, 1/((1-X)*(1-p*X))) + %1 = [1, 3, 4, 7, 6, 12, 8, 15, 13, 18] + + ? direuler(p=2, 10, 1/((1-X)*(1-p*X)), 5) \\ fewer terms + %2 = [1, 3, 4, 7, 6] + @eprog\noindent Setting $c < b$ is useless (the same effect would be + achieved by setting $b = c)$. If $c > b$, the computed coefficients are + ``missing'' Euler factors: + \bprog + ? direuler(p=2, 10, 1/((1-X)*(1-p*X)), 15) \\ more terms, no longer = sigma ! + %3 = [1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 0, 28, 0, 24, 24] + @eprog + + \synt{direuler}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN b} + +Function: dirmul +Class: basic +Section: number_theoretical +C-Name: dirmul +Prototype: GG +Help: dirmul(x,y): multiplication of the Dirichlet series x by the Dirichlet + series y. +Doc: $x$ and $y$ being vectors of perhaps different lengths representing + the \idx{Dirichlet series} $\sum_{n} x_{n} n^{-s}$ and $\sum_{n} y_{n} n^{-s}$, + computes the product of $x$ by $y$, again as a vector. + \bprog + ? dirmul(vector(10,n,1), vector(10,n,moebius(n))) + %1 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + @eprog\noindent + The product + length is the minimum of $\kbd{\#}x\kbd{*}v(y)$ and $\kbd{\#}y\kbd{*}v(x)$, + where $v(x)$ is the index of the first nonzero coefficient. + \bprog + ? dirmul([0,1], [0,1]); + %2 = [0, 0, 0, 1] + @eprog + +Function: dirpowers +Class: basic +Section: linear_algebra +C-Name: dirpowers +Prototype: LGp +Help: dirpowers(n,x): return the vector [1^x,2^x,...,n^x]. +Doc: for nonnegative $n$ and complex number $x$, return the vector with $n$ + components $[1^{x},2^{x},\dots,n^{x}]$. + \bprog + ? dirpowers(5, 2) + %1 = [1, 4, 9, 16, 25] + ? dirpowers(5, 1/2) + %2 = [1, 1.414..., 1.732..., 2.000..., 2.236...] + @eprog\noindent When $n \le 0$, the function returns the empty vector \kbd{[]}. + +Function: dirpowerssum +Class: basic +Section: number_theoretical +C-Name: dirpowerssum0 +Prototype: GGDGD0,L,p +Help: dirpowerssum(N,x,{f},{both=0}): + return f(1)1^x + f(2)2^x + ... + f(N)N^x, where f is a completely + multiplicative function (= 1 if omitted). If both is set, return the pair + for arguments (x, f) and (-1-x, conj(f)). If both=2, assume in addition + that f is real-valued. +Doc: for positive integer $N$ and complex number $x$, return the sum + $f(1)1^{x} + f(2)2^{x} + \dots + f(N)N^{x}$, where $f$ is a completely + multiplicative function. If $f$ is omitted, return + $1^{x} + \dots + N^{x}$. When $N \le 0$, the function returns $0$. + If \kbd{both} is set, return the pair for arguments $(x,f)$ and + $(-1-x,\overline{f})$. If \kbd{both=2}, assume in addition that $f$ is + real-valued (which is true when $f$ is omitted, i.e. represents the constant + function $f(n) = 1$). + + \misctitle{Caveat} when {\tt both} is set, the present implementation + assumes that $|f(n)|$ is either $0$ or $1$, which is the case for + Dirichlet characters. + + A vector-valued multiplicative function $f$ is allowed, in which case the + above conditions must be met componentwise and the vector length must + be constant. + + Unlike variants using \kbd{dirpowers(N,x)}, this function uses $O(\sqrt{N})$ + memory instead of $O(N)$. And it is faster for large $N$. The return value + is usually a floating point number, but it will be exact if the result + is an integer. On the other hand, rational numbers are converted to + floating point approximations, since they are likely to blow up for large $N$. + \bprog + ? dirpowers(5, 2) + %1 = [1, 4, 9, 16, 25] + ? vecsum(%) + %2 = 55 + ? dirpowerssum(5, 2) + %3 = 55 + ? dirpowerssum(5, -2) + %4 = 1.4636111111111111111111111111111111111 + ? \p200 + ? s = 1/2 + I * sqrt(3); N = 10^7; + ? dirpowerssum(N, s); + time = 11,425 ms. + ? vecsum(dirpowers(N, s)) + time = 19,365 ms. + ? dirpowerssum(N, s, n->kronecker(-23,n)) + time = 10,981 ms. + @eprog\noindent The \kbd{dirpowerssum} commands work with default stack size, + the \kbd{dirpowers} one requires a stacksize of at least 5GB. + + \synt{dirpowerssumfun}{ulong N, GEN x, void *E, GEN (*f)(void*, ulong, long), long prec}. When $f = \kbd{NULL}$, one may use + \fun{GEN}{dirpowerssum}{ulong N, GEN x, long prec}. + +Function: dirzetak +Class: basic +Section: number_fields +C-Name: dirzetak +Prototype: GG +Help: dirzetak(nf,b): Dirichlet series of the Dedekind zeta function of the + number field nf up to the bound b-1. +Doc: gives as a vector the first $b$ + coefficients of the \idx{Dedekind} zeta function of the number field $\var{nf}$ + considered as a \idx{Dirichlet series}. + +Function: divisors +Class: basic +Section: number_theoretical +C-Name: divisors0 +Prototype: GD0,L, +Help: divisors(x,{flag=0}): gives a vector formed by the divisors of x in + increasing order. If flag = 1, return pairs [d, factor(d)]. +Description: + (gen,?0):vec divisors($1) + (gen,1):vec divisors_factored($1) +Doc: creates a row vector whose components are the + divisors of $x$. The factorization of $x$ (as output by \tet{factor}) can + be used instead. If $\fl = 1$, return pairs $[d, \kbd{factor}(d)]$. + + By definition, these divisors are the products of the irreducible + factors of $n$, as produced by \kbd{factor(n)}, raised to appropriate + powers (no negative exponent may occur in the factorization). If $n$ is + an integer, they are the positive divisors, in increasing order. + + \bprog + ? divisors(12) + %1 = [1, 2, 3, 4, 6, 12] + ? divisors(12, 1) \\ include their factorization + %2 = [[1, matrix(0,2)], [2, Mat([2, 1])], [3, Mat([3, 1])], + [4, Mat([2, 2])], [6, [2, 1; 3, 1]], [12, [2, 2; 3, 1]]] + + ? divisors(x^4 + 2*x^3 + x^2) \\ also works for polynomials + %3 = [1, x, x^2, x + 1, x^2 + x, x^3 + x^2, x^2 + 2*x + 1, + x^3 + 2*x^2 + x, x^4 + 2*x^3 + x^2] + @eprog + + This function requires a lot of memory if $x$ has many divisors. The + following idiom runs through all divisors using very little memory, in no + particular order this time: + \bprog + F = factor(x); P = F[,1]; E = F[,2]; + forvec(e = vectorv(#E,i,[0,E[i]]), d = factorback(P,e); ...) + @eprog If the factorization of $d$ is also desired, then $[P,e]$ almost + provides it but not quite: $e$ may contain $0$ exponents, which are not + allowed in factorizations. These must be sieved out as in: + \bprog + ? tofact(P,E) = matreduce(Mat([P,E])); + ? tofact([2,3,5,7]~, [4,0,2,0]~) + %4 = + [2 4] + + [5 2] + @eprog We can then run the above loop with \kbd{tofact(P,e)} instead of, + or together with, \kbd{factorback}. +Variant: The functions \fun{GEN}{divisors}{GEN N} ($\fl = 0$) and + \fun{GEN}{divisors_factored}{GEN N} ($\fl = 1$) are also available. + +Function: divisorslenstra +Class: basic +Section: number_theoretical +C-Name: divisorslenstra +Prototype: GGG +Help: divisorslenstra(N,r,s): finds all divisors d of N such that d = r + (mod s). Assume that (r,s) = 1 and s^3 > N. +Doc: Given three integers $N > s > r \geq 0$ such that $(r,s) = 1$ + and $s^{3} > N$, find all divisors $d$ of $N$ such that $d \equiv r \pmod{s}$. + There are at most $11$ such divisors (Lenstra). + \bprog + ? N = 245784; r = 19; s = 65 ; + ? divisorslenstra(N, r, s) + %2 = [19, 84, 539, 1254, 3724, 245784] + ? [ d | d <- divisors(N), d % s == r] + %3 = [19, 84, 539, 1254, 3724, 245784] + @eprog\noindent When the preconditions are not met, the result is undefined: + \bprog + ? N = 4484075232; r = 7; s = 1303; s^3 > N + %4 = 0 + ? divisorslenstra(N, r, s) + ? [ d | d <- divisors(N), d % s == r ] + %6 = [7, 2613, 9128, 19552, 264516, 3407352, 344928864] + @eprog\noindent (Divisors were missing but $s^{3} < N$.) + +Function: divrem +Class: basic +Section: operators +C-Name: divrem +Prototype: GGDn +Help: divrem(x,y,{v}): euclidean division of x by y giving as a + 2-dimensional column vector the quotient and the remainder, with respect to + v (to main variable if v is omitted). +Doc: creates a column vector with two components, the first being the Euclidean + quotient (\kbd{$x$ \bs\ $y$}), the second the Euclidean remainder + (\kbd{$x$ - ($x$\bs$y$)*$y$}), of the division of $x$ by $y$. This avoids the + need to do two divisions if one needs both the quotient and the remainder. + If $v$ is present, and $x$, $y$ are multivariate + polynomials, divide with respect to the variable $v$. + + Beware that \kbd{divrem($x$,$y$)[2]} is in general not the same as + \kbd{$x$ \% $y$}; no GP operator corresponds to it: + \bprog + ? divrem(1/2, 3)[2] + %1 = 1/2 + ? (1/2) % 3 + %2 = 2 + ? divrem(Mod(2,9), 3)[2] + *** at top-level: divrem(Mod(2,9),3)[2 + *** ^-------------------- + *** forbidden division t_INTMOD \ t_INT. + ? Mod(2,9) % 6 + %3 = Mod(2,3) + @eprog +Variant: Also available is \fun{GEN}{gdiventres}{GEN x, GEN y} when $v$ is + not needed. + +Function: eint1 +Class: basic +Section: transcendental +C-Name: veceint1 +Prototype: GDGp +Help: eint1(x,{n}): exponential integral E1(x). If n is present and x > 0, + computes the vector of the first n values of the exponential integral E1(n x). +Doc: exponential integral $\int_{x}^{\infty} \dfrac{e^{-t}}{t}\,dt = + \kbd{incgam}(0, x)$, where the latter expression extends the function + definition from real $x > 0$ to all complex $x \neq 0$. + + If $n$ is present, we must have $x > 0$; the function returns the + $n$-dimensional vector $[\kbd{eint1}(x),\dots,\kbd{eint1}(nx)]$. Contrary to + other transcendental functions, and to the default case ($n$ omitted), the + values are correct up to a bounded \emph{absolute}, rather than relative, + error $10^{-n}$, where $n$ is \kbd{precision}$(x)$ if $x$ is a \typ{REAL} + and defaults to \kbd{realprecision} otherwise. (In the most important + application, to the computation of $L$-functions via approximate functional + equations, those values appear as weights in long sums and small individual + relative errors are less useful than controlling the absolute error.) This is + faster than repeatedly calling \kbd{eint1($i$ * x)}, but less precise. +Variant: Also available is \fun{GEN}{eint1}{GEN x, long prec}. + +Function: ell2cover +Class: basic +Section: elliptic_curves +C-Name: ell2cover +Prototype: Gp +Help: ell2cover(E): if E is an elliptic curve over Q, returns a basis of the + set of everywhere locally soluble 2-covers of the curve E. For each cover a + pair [R,P] is returned where y^2-R(x) is a quartic curve and P belongs to + E(k), where k = Q(x)[y] / (y^2-R(x)). +Doc: if $E$ is an elliptic curve over $\Q$, returns a basis of the set of + everywhere locally soluble $2$-covers of the curve $E$. + For each cover a pair $[R,P]$ is returned where $y^{2}-R(x)$ is a quartic curve + and $P$ is a point on $E(k)$, where $k = \Q(x)[y] / (y^{2}-R(x))$. + $E$ can also be given as the output of \kbd{ellrankinit(E)}, + or as a pair $[e, f]$, where $e$ is an elliptic curve given by + \kbd{ellrankinit} and $f$ is a quadratic twist of $e$. We then look for + points on $f$. + \bprog + ? E = ellinit([-25,4]); + ? C = ell2cover(E); #C + %2 = 2 + ? [R,P] = C[1]; R + %3 = 64*x^4+480*x^2-128*x+100 + ? P[1] + %4 = -320/y^2*x^4 + 256/y^2*x^3 + 800/y^2*x^2 - 320/y^2*x - 436/y^2 + ? ellisoncurve(E, Mod(P, y^2-R)) + %5 = 1 + ? H = hyperellratpoints(R,10) + %6 = [[0,10], [0,-10], [1/5,242/25], [1/5,-242/25], [2/5,282/25], + [2/5,-282/25]] + ? A = substvec(P,[x,y],H[1]) + %7 = [-109/25, 686/125] + @eprog + +Function: ellE +Class: basic +Section: transcendental +C-Name: ellE +Prototype: Gp +Help: ellE(k): Complete elliptic integral of the second kind for the + complex parameter k using the agm. +Doc: Complete elliptic integral of the second kind + $$E(k)=\int_{0}^{\pi/2}(1-k^{2}\sin(t)^{2})^{1/2}\,dt$$ for the + complex parameter $k$ using the agm. + + In particular, the perimeter of an ellipse of semi-major and semi-minor axes + $a$ and $b$ is given by + \bprog + e = sqrt(1 - (b/a)^2); \\ eccentricity + 4 * a * ellE(e) \\ perimeter + @eprog + +Function: ellK +Class: basic +Section: transcendental +C-Name: ellK +Prototype: Gp +Help: ellK(k): Complete elliptic integral of the first kind for the + complex parameter k using the agm. +Doc: Complete elliptic integral of the first kind + $$K(k)=\int_{0}^{\pi/2}(1-k^{2}\sin(t)^{2})^{-1/2}\,dt$$ for the + complex parameter $k$ using the agm. + +Function: ellL1 +Class: basic +Section: elliptic_curves +C-Name: ellL1 +Prototype: GD0,L,b +Help: ellL1(E,{r=0}): returns the value at s=1 of the derivative of order r of + the L-function of the elliptic curve E. +Doc: returns the value at $s=1$ of the derivative of order $r$ of the + $L$-function of the elliptic curve $E/\Q$. + \bprog + ? E = ellinit("11a1"); \\ order of vanishing is 0 + ? ellL1(E) + %2 = 0.2538418608559106843377589233 + ? E = ellinit("389a1"); \\ order of vanishing is 2 + ? ellL1(E) + %4 = -5.384067311837218089235032414 E-29 + ? ellL1(E, 1) + %5 = 0 + ? ellL1(E, 2) + %6 = 1.518633000576853540460385214 + @eprog\noindent + The main use of this function, after computing at \emph{low} accuracy the + order of vanishing using \tet{ellanalyticrank}, is to compute the + leading term at \emph{high} accuracy to check (or use) the Birch and + Swinnerton-Dyer conjecture: + \bprog + ? \p18 + realprecision = 18 significant digits + ? E = ellinit("5077a1"); ellanalyticrank(E) + time = 8 ms. + %1 = [3, 10.3910994007158041] + ? \p200 + realprecision = 202 significant digits (200 digits displayed) + ? ellL1(E, 3) + time = 104 ms. + %3 = 10.3910994007158041387518505103609170697263563756570092797@com$[\dots]$ + @eprog\noindent Analogous and more general functionalities for $E$ + defined over general number fields are available through \kbd{lfun}. + +Function: elladd +Class: basic +Section: elliptic_curves +C-Name: elladd +Prototype: GGG +Help: elladd(E,z1,z2): sum of the points z1 and z2 on elliptic curve E. +Doc: + sum of the points $z1$ and $z2$ on the + elliptic curve corresponding to $E$. + +Function: ellak +Class: basic +Section: elliptic_curves +C-Name: akell +Prototype: GG +Help: ellak(E,n): computes the n-th Fourier coefficient of the L-function of + the elliptic curve E (assumes E is an integral model). +Doc: + computes the coefficient $a_{n}$ of the $L$-function of the elliptic curve + $E/\Q$, i.e.~coefficients of a newform of weight 2 by the modularity theorem + (\idx{Taniyama-Shimura-Weil conjecture}). $E$ must be an \kbd{ell} structure + over $\Q$ as output by \kbd{ellinit}. $E$ must be given by an integral model, + not necessarily minimal, although a minimal model will make the function + faster. + \bprog + ? E = ellinit([1,-1,0,4,3]); + ? ellak(E, 10) + %2 = -3 + ? e = ellchangecurve(E, [1/5,0,0,0]); \\ made not minimal at 5 + ? ellak(e, 10) \\ wasteful but works + %3 = -3 + ? E = ellminimalmodel(e); \\ now minimal + ? ellak(E, 5) + %5 = -3 + @eprog\noindent If the model is not minimal at a number of bad primes, then + the function will be slower on those $n$ divisible by the bad primes. + The speed should be comparable for other $n$: + \bprog + ? for(i=1,10^6, ellak(E,5)) + time = 699 ms. + ? for(i=1,10^6, ellak(e,5)) \\ 5 is bad, markedly slower + time = 1,079 ms. + + ? for(i=1,10^5,ellak(E,5*i)) + time = 1,477 ms. + ? for(i=1,10^5,ellak(e,5*i)) \\ still slower but not so much on average + time = 1,569 ms. + @eprog + +Function: ellan +Class: basic +Section: elliptic_curves +C-Name: ellan +Prototype: GL +Help: ellan(E,n): computes the first n Fourier coefficients of the + L-function of the elliptic curve E defined over a number field. +Doc: computes the vector of the first $n$ Fourier coefficients $a_{k}$ + corresponding to the elliptic curve $E$ defined over a number field. + If $E$ is defined over $\Q$, the curve may be given by an + arbitrary model, not necessarily minimal, + although a minimal model will make the function faster. Over a more general + number field, the model must be locally minimal at all primes above $2$ + and $3$. +Variant: Also available is \fun{GEN}{ellanQ_zv}{GEN e, long n}, which + returns a \typ{VECSMALL} instead of a \typ{VEC}, saving on memory. + +Function: ellanalyticrank +Class: basic +Section: elliptic_curves +C-Name: ellanalyticrank +Prototype: GDGb +Help: ellanalyticrank(E,{eps}): returns the order of vanishing at s=1 + of the L-function of the elliptic curve E and the value of the first + nonzero derivative. To determine this order, it is assumed that any + value less than eps is zero. If no value of eps is given, 2^(-bitprecision/2) + is used. +Doc: returns the order of vanishing at $s=1$ of the $L$-function of the + elliptic curve $E/\Q$ and the value of the first nonzero derivative. To + determine this order, it is assumed that any value less than \kbd{eps} is + zero. If \kbd{eps} is omitted, $2^{-b/2}$ is used, where $b$ + is the current bit precision. + \bprog + ? E = ellinit("11a1"); \\ rank 0 + ? ellanalyticrank(E) + %2 = [0, 0.2538418608559106843377589233] + ? E = ellinit("37a1"); \\ rank 1 + ? ellanalyticrank(E) + %4 = [1, 0.3059997738340523018204836835] + ? E = ellinit("389a1"); \\ rank 2 + ? ellanalyticrank(E) + %6 = [2, 1.518633000576853540460385214] + ? E = ellinit("5077a1"); \\ rank 3 + ? ellanalyticrank(E) + %8 = [3, 10.39109940071580413875185035] + @eprog\noindent Analogous and more general functionalities for $E$ + defined over general number fields are available through \kbd{lfun} + and \kbd{lfunorderzero}. + +Function: ellap +Class: basic +Section: elliptic_curves +C-Name: ellap +Prototype: GDG +Help: ellap(E,{p}): given an elliptic curve E defined over + a finite field Fq, return the trace of Frobenius a_p = q+1-#E(Fq); for other + fields of definition K, p must define a finite residue field, + (p prime for K = Qp or Q; p a maximal ideal for K a number field), + return the order of the (nonsingular) reduction of E. +Doc: + Let \kbd{E} be an \kbd{ell} structure as output by \kbd{ellinit}, attached + to an elliptic curve $E/K$. If the field $K = \F_{q}$ is finite, return the + trace of Frobenius $t$, defined by the equation $\#E(\F_{q}) = q+1 - t$. + + For other fields of definition and $p$ defining a finite residue field + $\F_{q}$, return the trace of Frobenius for the reduction of $E$: the argument + $p$ is best left omitted if $K = \Q_{\ell}$ (else we must have $p = \ell$) and + must be a prime number ($K = \Q$) or prime ideal ($K$ a general number field) + with residue field $\F_{q}$ otherwise. The equation need not be minimal + or even integral at $p$; of course, a minimal model will be more efficient. + + For a number field $K$, the trace of Frobenius is the $a_{p}$ + coefficient in the Euler product defining the curve $L$-series, whence + the function name: + $$L(E/K,s) = \prod_{\text{bad}\ p} (1-a_{p} (Np)^{-s})^{-1} + \prod_{\text{good}\ p} (1-a_{p} (Np)^{-s} + (Np)^{1-2s})^{-1}. $$ + + When the characteristic of the finite field is large, the availability of + the \kbd{seadata} package will speed up the computation. + + \bprog + ? E = ellinit([0,1]); \\ y^2 = x^3 + 0.x + 1, defined over Q + ? ellap(E, 7) \\ 7 necessary here + %2 = -4 \\ #E(F_7) = 7+1-(-4) = 12 + ? ellcard(E, 7) + %3 = 12 \\ OK + + ? E = ellinit([0,1], 11); \\ defined over F_11 + ? ellap(E) \\ no need to repeat 11 + %4 = 0 + ? ellap(E, 11) \\ ... but it also works + %5 = 0 + ? ellgroup(E, 13) \\ ouch, inconsistent input! + *** at top-level: ellap(E,13) + *** ^----------- + *** ellap: inconsistent moduli in Rg_to_Fp: + 11 + 13 + ? a = ffgen(ffinit(11,3), 'a); \\ defines F_q := F_{11^3} + ? E = ellinit([a+1,a]); \\ y^2 = x^3 + (a+1)x + a, defined over F_q + ? ellap(E) + %8 = -3 + @eprog + + If the curve is defined over a more general number field than $\Q$, + the maximal ideal $p$ must be explicitly given in \kbd{idealprimedec} + format. There is no assumption of local minimality at $p$. + \bprog + ? K = nfinit(a^2+1); E = ellinit([1+a,0,1,0,0], K); + ? fa = idealfactor(K, E.disc) + %2 = + [ [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] 1] + + [[13, [5, 1]~, 1, 1, [-5, -1; 1, -5]] 2] + ? ellap(E, fa[1,1]) + %3 = -1 \\ nonsplit multiplicative reduction + ? ellap(E, fa[2,1]) + %4 = 1 \\ split multiplicative reduction + ? P17 = idealprimedec(K,17)[1]; + ? ellap(E, P17) + %6 = 6 \\ good reduction + ? E2 = ellchangecurve(E, [17,0,0,0]); + ? ellap(E2, P17) + %8 = 6 \\ same, starting from a nonminimal model + + ? P3 = idealprimedec(K,3)[1]; + ? ellap(E, P3) \\ OK: E is minimal at P3 + %10 = -2 + ? E3 = ellchangecurve(E, [3,0,0,0]); + ? ellap(E3, P3) \\ not integral at P3 + *** at top-level: ellap(E3,P3) + *** ^------------ + *** ellap: impossible inverse in Rg_to_ff: Mod(0, 3). + @eprog + + \misctitle{Algorithms used} If $E/\F_{q}$ has CM by a principal imaginary + quadratic order we use a fast explicit formula (involving essentially + Kronecker symbols and Cornacchia's algorithm), in $O(\log q)^{2}$ bit + operations. + Otherwise, we use Shanks-Mestre's baby-step/giant-step method, which runs in + time $\tilde{O}(q^{1/4})$ using $\tilde{O}(q^{1/4})$ storage, hence becomes + unreasonable when $q$ has about 30~digits. Above this range, the \tet{SEA} + algorithm becomes available, heuristically in $\tilde{O}(\log q)^{4}$, and + primes of the order of 200~digits become feasible. In small + characteristic we use Mestre's (p=2), Kohel's (p=3,5,7,13), Satoh-Harley + (all in $\tilde{O}(p^{2}\*n^{2})$) or Kedlaya's (in $\tilde{O}(p\*n^{3})$) + algorithms. + +Function: ellbil +Class: basic +Section: elliptic_curves +C-Name: bilhell +Prototype: GGGp +Obsolete: 2014-05-21 +Help: ellbil(E,z1,z2): deprecated alias for ellheight(E,P,Q). +Doc: deprecated alias for \kbd{ellheight(E,P,Q)}. + +Function: ellbsd +Class: basic +Section: elliptic_curves +C-Name: ellbsd +Prototype: Gp +Help: ellbsd(E): E being an elliptic curve over a number field, + returns a real number c such that the BSD conjecture predicts that + lfun(E,1,r)/r! = c*R*S where r is the rank, R is the regulator and S is the + cardinal of the Tate-Shafarevich group. +Doc: + $E$ being an elliptic curve over a number field, returns a real + number $c$ such that the Birch and Swinnerton-Dyer conjecture predicts that + $L_{E}^{(r)}(1)/r!{} = c\*R\*S$, where $r$ is the rank, $R$ the regulator and + $S$ the cardinal of the Tate-Shafarevich group. + + \bprog + ? e = ellinit([0,-1,1,-10,-20]); \\ rank 0 + ? ellbsd(e) + %2 = 0.25384186085591068433775892335090946105 + ? lfun(e,1) + %3 = 0.25384186085591068433775892335090946104 + ? e = ellinit([0,0,1,-1,0]); \\ rank 1 + ? P = ellheegner(e); + ? ellbsd(e)*ellheight(e,P) + %6 = 0.30599977383405230182048368332167647445 + ? lfun(e,1,1) + %7 = 0.30599977383405230182048368332167647445 + ? e = ellinit([1+a,0,1,0,0],nfinit(a^2+1)); \\ rank 0 + ? ellbsd(e) + %9 = 0.42521832235345764503001271536611593310 + ? lfun(e,1) + %10 = 0.42521832235345764503001271536611593309 + @eprog + +Function: ellcard +Class: basic +Section: elliptic_curves +C-Name: ellcard +Prototype: GDG +Help: ellcard(E,{p}): given an elliptic curve E defined over + a finite field Fq, return the order of the group E(Fq); for other fields + of definition K, p must define a finite residue field, + (p prime for K = Qp or Q; p a maximal ideal for K a number field), + return the order of the (nonsingular) reduction of E. +Doc: Let \kbd{E} be an \kbd{ell} structure as output by \kbd{ellinit}, attached + to an elliptic curve $E/K$. If $K = \F_{q}$ is finite, return the order of the + group $E(\F_{q})$. + \bprog + ? E = ellinit([-3,1], 5); ellcard(E) + %1 = 7 + ? t = ffgen(3^5,'t); E = ellinit([t,t^2+1]); ellcard(E) + %2 = 217 + @eprog\noindent + For other fields of definition and $p$ defining a finite residue field + $\F_{q}$, return the order of the reduction of $E$: the argument $p$ is best + left omitted if $K = \Q_{\ell}$ (else we must have $p = \ell$) and must be a + prime number ($K = \Q$) or prime ideal ($K$ a general number field) with + residue field $\F_{q}$ otherwise. The equation need not be minimal + or even integral at $p$; of course, a minimal model will be more efficient. + The function considers the group of nonsingular points of the reduction + of a minimal model of the curve at $p$, so also makes sense when the curve + has bad reduction. + \bprog + ? E = ellinit([-3,1]); + ? factor(E.disc) + %2 = + [2 4] + + [3 4] + ? ellcard(E, 5) \\ as above ! + %3 = 7 + ? ellcard(E, 2) \\ additive reduction + %4 = 2 + @eprog + + When the characteristic of the finite field is large, the availability of + the \kbd{seadata} package will speed the computation. See also \tet{ellap} + for the list of implemented algorithms. +Variant: Also available is \fun{GEN}{ellcard}{GEN E, GEN p} where $p$ is not + \kbd{NULL}. + +Function: ellchangecurve +Class: basic +Section: elliptic_curves +C-Name: ellchangecurve +Prototype: GG +Help: ellchangecurve(E,v): change data on elliptic curve according to + v=[u,r,s,t]. +Description: + (gen, gen):ell ellchangecurve($1, $2) +Doc: + changes the data for the elliptic curve $E$ + by changing the coordinates using the vector \kbd{v=[u,r,s,t]}, i.e.~if $x'$ + and $y'$ are the new coordinates, then $x=u^{2}x'+r$, $y=u^{3}y'+su^{2}x'+t$. + $E$ must be an \kbd{ell} structure as output by \kbd{ellinit}. The special + case $v = 1$ is also used instead of $[1,0,0,0]$ to denote the + trivial coordinate change. + +Function: ellchangepoint +Class: basic +Section: elliptic_curves +C-Name: ellchangepoint +Prototype: GG +Help: ellchangepoint(x,v): change data on point or vector of points x on an + elliptic curve according to v=[u,r,s,t]. +Doc: + changes the coordinates of the point or + vector of points $x$ using the vector \kbd{v=[u,r,s,t]}, i.e.~if $x'$ and + $y'$ are the new coordinates, then $x=u^{2}x'+r$, $y=u^{3}y'+su^{2}x'+t$ + (see also \kbd{ellchangecurve}). + \bprog + ? E0 = ellinit([1,1]); P0 = [0,1]; v = [1,2,3,4]; + ? E = ellchangecurve(E0, v); + ? P = ellchangepoint(P0,v) + %3 = [-2, 3] + ? ellisoncurve(E, P) + %4 = 1 + ? ellchangepointinv(P,v) + %5 = [0, 1] + @eprog +Variant: The reciprocal function \fun{GEN}{ellchangepointinv}{GEN x, GEN ch} + inverts the coordinate change. + +Function: ellchangepointinv +Class: basic +Section: elliptic_curves +C-Name: ellchangepointinv +Prototype: GG +Help: ellchangepointinv(x,v): change data on point or vector of points x on an + elliptic curve according to v=[u,r,s,t], inverse of ellchangepoint. +Doc: + changes the coordinates of the point or vector of points $x$ using + the inverse of the isomorphism attached to \kbd{v=[u,r,s,t]}, + i.e.~if $x'$ and $y'$ are the old coordinates, then $x=u^{2}x'+r$, + $y=u^{3}y'+su^{2}x'+t$ (inverse of \kbd{ellchangepoint}). + \bprog + ? E0 = ellinit([1,1]); P0 = [0,1]; v = [1,2,3,4]; + ? E = ellchangecurve(E0, v); + ? P = ellchangepoint(P0,v) + %3 = [-2, 3] + ? ellisoncurve(E, P) + %4 = 1 + ? ellchangepointinv(P,v) + %5 = [0, 1] \\ we get back P0 + @eprog + +Function: ellconvertname +Class: basic +Section: elliptic_curves +C-Name: ellconvertname +Prototype: G +Help: ellconvertname(name): convert an elliptic curve name (as found in + the elldata database) from a string to a triplet [conductor, isogeny class, + index]. It will also convert a triplet back to a curve name. +Doc: + converts an elliptic curve name, as found in the \tet{elldata} database, + from a string to a triplet $[\var{conductor}, \var{isogeny class}, + \var{index}]$. It will also convert a triplet back to a curve name. + Examples: + \bprog + ? ellconvertname("123b1") + %1 = [123, 1, 1] + ? ellconvertname(%) + %2 = "123b1" + @eprog + +Function: elldivpol +Class: basic +Section: elliptic_curves +C-Name: elldivpol +Prototype: GLDn +Help: elldivpol(E,n,{v='x}): n-division polynomial f_n for the curve E in the + variable v. +Doc: $n$-division polynomial $f_{n}$ for the curve $E$ in the + variable $v$. In standard notation, for any affine point $P = (X,Y)$ on the + curve and any integer $n \geq 0$, we have + $$[n]P = (\phi_{n}(P)\psi_{n}(P) : \omega_{n}(P) : \psi_{n}(P)^{3})$$ + for some polynomials $\phi_{n},\omega_{n},\psi_{n}$ in + $\Z[a_{1},a_{2},a_{3},a_{4},a_{6}][X,Y]$. We have $f_{n}(X) = \psi_{n}(X)$ + for $n$ odd, and + $f_{n}(X) = \psi_{n}(X,Y) (2Y + a_{1}X+a_{3})$ for $n$ even. We have + $$ f_{0} = 0,\quad f_{1} = 1,\quad + f_{2} = 4X^{3} + b_{2}X^{2} + 2b_{4} X + b_{6}, \quad + f_{3} = 3 X^{4} + b_{2} X^{3} + 3b_{4} X^{2} + 3 b_{6} X + b8, $$ + $$ f_{4} = f_{2}(2X^{6} + b_{2} X^{5} + 5b_{4} X^{4} + 10 b_{6} X^{3} + + 10 b_{8} X^{2} + (b_{2}b_{8}-b_{4}b_{6})X + (b_{8}b_{4} - b_{6}^{2})), + \dots $$ + When $n$ is odd, the roots of $f_{n}$ are the $X$-coordinates of the affine + points in the $n$-torsion subgroup $E[n]$; when $n$ is even, the roots + of $f_{n}$ are the $X$-coordinates of the affine points in $E[n]\setminus + E[2]$ when $n > 2$, resp.~in $E[2]$ when $n = 2$. + For $n < 0$, we define $f_{n} := - f_{-n}$. + +Function: elleisnum +Class: basic +Section: elliptic_curves +C-Name: elleisnum +Prototype: GLD0,L,p +Help: elleisnum(w,k,{flag=0}): k being an even positive integer, computes the + numerical value of the Eisenstein series of weight k at the lattice + w, as given by ellperiods. When flag is nonzero and k=4 or 6, this gives the + elliptic invariants g2 or g3 with the correct normalization. +Doc: $k$ being an even positive integer, computes the numerical value of the + Eisenstein series of weight $k$ at the lattice $w$, as given by + \tet{ellperiods}, namely + $$ + (2i \pi/\omega_{2})^{k} + \Big(1 + 2/\zeta(1-k) \sum_{n\geq 1} n^{k-1}q^{n} / (1-q^{n})\Big), + $$ + where $q = \exp(2i\pi \tau)$ and $\tau:=\omega_{1}/\omega_{2}$ belongs to the + complex upper half-plane. It is also possible to directly input $w = + [\omega_{1},\omega_{2}]$, or an elliptic curve $E$ as given by \kbd{ellinit}. + \bprog + ? w = ellperiods([1,I]); + ? elleisnum(w, 4) + %2 = 2268.8726415508062275167367584190557607 + ? elleisnum(w, 6) + %3 = -3.977978632282564763 E-33 + ? E = ellinit([1, 0]); + ? elleisnum(E, 4) + %5 = -48.000000000000000000000000000000000000 + @eprog + + When \fl\ is nonzero and $k=4$ or 6, returns the elliptic invariants $g_{2}$ + or $g_{3}$, such that + $$y^{2} = 4x^{3} - g_{2} x - g_{3}$$ + is a Weierstrass equation for $E$. + \bprog + ? g2 = elleisnum(E, 4, 1) + %6 = -4.0000000000000000000000000000000000000 + ? g3 = elleisnum(E, 6, 1) \\ ~ 0 + %7 = 0.E-114 - 3.909948178422242682 E-57*I + @eprog + +Function: elleta +Class: basic +Section: elliptic_curves +C-Name: elleta +Prototype: Gp +Help: elleta(w): w=[w1,w2], returns the vector [eta1,eta2] of quasi-periods + attached to [w1,w2]. +Doc: returns the quasi-periods $[\eta_{1},\eta_{2}]$ + attached to the lattice basis $\var{w} = [\omega_{1}, \omega_{2}]$. + Alternatively, \var{w} can be an elliptic curve $E$ as output by + \kbd{ellinit}, in which case, the quasi periods attached to the period + lattice basis \kbd{$E$.omega} (namely, \kbd{$E$.eta}) are returned. + \bprog + ? elleta([1, I]) + %1 = [3.141592653589793238462643383, 9.424777960769379715387930149*I] + @eprog + +Function: ellformaldifferential +Class: basic +Section: elliptic_curves +C-Name: ellformaldifferential +Prototype: GDPDn +Help: ellformaldifferential(E,{n=seriesprecision},{t='x}) : E elliptic curve, + n integer. Returns n terms of the power series [f, g] such that + omega = dx/(2y+a_1x+a_3) = f(t) dt and eta = x(t) * omega = g(t) dt in the + local parameter t=-x/y. +Doc: Let $\omega := dx / (2y+a_{1}x+a_{3})$ be the invariant differential form + attached to the model $E$ of some elliptic curve (\kbd{ellinit} form), + and $\eta := x(t)\omega$. Return $n$ terms (\tet{seriesprecision} by default) + of $f(t),g(t)$ two power series in the formal parameter $t=-x/y$ such that + $\omega = f(t) dt$, $\eta = g(t) dt$: + $$f(t) = 1+a_{1} t + (a_{1}^{2} + a_{2}) t^{2} + \dots,\quad + g(t) = t^{-2} +\dots $$ + \bprog + ? E = ellinit([-1,1/4]); [f,g] = ellformaldifferential(E,7,'t); + ? f + %2 = 1 - 2*t^4 + 3/4*t^6 + O(t^7) + ? g + %3 = t^-2 - t^2 + 1/2*t^4 + O(t^5) + @eprog + +Function: ellformalexp +Class: basic +Section: elliptic_curves +C-Name: ellformalexp +Prototype: GDPDn +Help: ellformalexp(E,{n=seriesprecision},{z='x}): E elliptic curve, + returns n terms of the formal elliptic exponential on E as a series in z. +Doc: The elliptic formal exponential \kbd{Exp} attached to $E$ is the + isomorphism from the formal additive law to the formal group of $E$. It is + normalized so as to be the inverse of the elliptic logarithm (see + \tet{ellformallog}): $\kbd{Exp} \circ L = \Id$. Return $n$ terms of this + power series: + \bprog + ? E=ellinit([-1,1/4]); Exp = ellformalexp(E,10,'z) + %1 = z + 2/5*z^5 - 3/28*z^7 + 2/15*z^9 + O(z^11) + ? L = ellformallog(E,10,'t); + ? subst(Exp,z,L) + %3 = t + O(t^11) + @eprog + +Function: ellformallog +Class: basic +Section: elliptic_curves +C-Name: ellformallog +Prototype: GDPDn +Help: ellformallog(E,{n=seriesprecision},{v='x}): E elliptic curve, + returns n terms of the elliptic logarithm as a series of t =-x/y. +Doc: The formal elliptic logarithm is a series $L$ in $t K[[t]]$ + such that $d L = \omega = dx / (2y + a_{1}x + a_{3})$, the canonical invariant + differential attached to the model $E$. It gives an isomorphism + from the formal group of $E$ to the additive formal group. + \bprog + ? E = ellinit([-1,1/4]); L = ellformallog(E, 9, 't) + %1 = t - 2/5*t^5 + 3/28*t^7 + 2/3*t^9 + O(t^10) + ? [f,g] = ellformaldifferential(E,8,'t); + ? L' - f + %3 = O(t^8) + @eprog + +Function: ellformalpoint +Class: basic +Section: elliptic_curves +C-Name: ellformalpoint +Prototype: GDPDn +Help: ellformalpoint(E,{n=seriesprecision},{v='x}): E elliptic curve, + n integer; return the coordinates [x(t), y(t)] on the elliptic curve as a + formal expansion in the formal parameter t = -x/y. +Doc: If $E$ is an elliptic curve, return the coordinates $x(t), y(t)$ in the + formal group of the elliptic curve $E$ in the formal parameter $t = -x/y$ + at $\infty$: + $$ x = t^{-2} -a_{1} t^{-1} - a_{2} - a_{3} t + \dots $$ + $$ y = - t^{-3} -a_{1} t^{-2} - a_{2}t^{-1} -a_{3} + \dots $$ + Return $n$ terms (\tet{seriesprecision} by default) of these two power + series, whose coefficients are in $\Z[a_{1},a_{2},a_{3},a_{4},a_{6}]$. + \bprog + ? E = ellinit([0,0,1,-1,0]); [x,y] = ellformalpoint(E,8,'t); + ? x + %2 = t^-2 - t + t^2 - t^4 + 2*t^5 + O(t^6) + ? y + %3 = -t^-3 + 1 - t + t^3 - 2*t^4 + O(t^5) + ? E = ellinit([0,1/2]); ellformalpoint(E,7) + %4 = [x^-2 - 1/2*x^4 + O(x^5), -x^-3 + 1/2*x^3 + O(x^4)] + @eprog + +Function: ellformalw +Class: basic +Section: elliptic_curves +C-Name: ellformalw +Prototype: GDPDn +Help: ellformalw(E,{n=seriesprecision},{t='x}): E elliptic curve, + n integer; returns n terms of the formal expansion of w = -1/y in the formal + parameter t = -x/y. +Doc: Return the formal power series $w$ attached to the elliptic curve $E$, + in the variable $t$: + $$ w(t) = t^{3}(1 + a_{1} t + (a_{2} + a_{1}^{2}) t^{2} + \cdots + O(t^{n})),$$ + which is the formal expansion of $-1/y$ in the formal parameter $t := -x/y$ + at $\infty$ (take $n = \tet{seriesprecision}$ if $n$ is omitted). The + coefficients of $w$ belong to $\Z[a_{1},a_{2},a_{3},a_{4},a_{6}]$. + \bprog + ? E=ellinit([3,2,-4,-2,5]); ellformalw(E, 5, 't) + %1 = t^3 + 3*t^4 + 11*t^5 + 35*t^6 + 101*t^7 + O(t^8) + @eprog + +Function: ellfromeqn +Class: basic +Section: elliptic_curves +C-Name: ellfromeqn +Prototype: G +Help: ellfromeqn(P): given a genus 1 plane curve, defined by the affine + equation f(x,y) = 0, return the coefficients [a1,a2,a3,a4,a6] of a + Weierstrass equation for its Jacobian. + This allows to recover a Weierstrass model for an elliptic curve given by a + general plane cubic or by a binary quartic or biquadratic model. +Doc: + Given a genus $1$ plane curve, defined by the affine equation $f(x,y) = 0$, + return the coefficients $[a_{1},a_{2},a_{3},a_{4},a_{6}]$ of a Weierstrass + equation for its Jacobian. This allows to recover a Weierstrass model for an + elliptic curve given by a general plane cubic or by a binary quartic or + biquadratic model. The function implements the $f \mapsto f^{*}$ formulae of + Artin, Tate and Villegas (Advances in Math. 198 (2005), pp. 366--382). + + In the example below, the function is used to convert between twisted Edwards + coordinates and Weierstrass coordinates. + \bprog + ? e = ellfromeqn(a*x^2+y^2 - (1+d*x^2*y^2)) + %1 = [0, -a - d, 0, -4*d*a, 4*d*a^2 + 4*d^2*a] + ? E = ellinit(ellfromeqn(y^2-x^2 - 1 +(121665/121666*x^2*y^2)),2^255-19); + ? isprime(ellcard(E) / 8) + %3 = 1 + @eprog + + The elliptic curve attached to the sum of two cubes is given by + \bprog + ? ellfromeqn(x^3+y^3 - a) + %1 = [0, 0, -9*a, 0, -27*a^2] + @eprog + + \misctitle{Congruent number problem} + Let $n$ be an integer, if $a^{2}+b^{2}=c^{2}$ and $a\*b=2\*n$, + then by substituting $b$ by $2\*n/a$ in the first equation, + we get $((a^{2}+(2\*n/a)^{2})-c^{2})\*a^{2} = 0$. + We set $x=a$, $y=a\*c$. + \bprog + ? En = ellfromeqn((x^2 + (2*n/x)^2 - (y/x)^2)*x^2) + %1 = [0, 0, 0, -16*n^2, 0] + @eprog + For example $23$ is congruent since the curve has a point of infinite order, + namely: + \bprog + ? ellheegner( ellinit(subst(En, n, 23)) ) + %2 = [168100/289, 68053440/4913] + @eprog + +Function: ellfromj +Class: basic +Section: elliptic_curves +C-Name: ellfromj +Prototype: G +Help: ellfromj(j): returns the coefficients [a1,a2,a3,a4,a6] of a fixed + elliptic curve with j-invariant j. +Doc: returns the coefficients $[a_{1},a_{2},a_{3},a_{4},a_{6}]$ of a fixed + elliptic curve + with $j$-invariant $j$. The given model is arbitrary; for instance, over the + rationals, it is in general not minimal nor even integral. + \bprog + ? v = ellfromj(1/2) + %1 = [0, 0, 0, 10365/4, 11937025/4] + ? E = ellminimalmodel(ellinit(v)); E[1..5] + %2 = [0, 0, 0, 41460, 190992400] + ? F = ellminimalmodel(elltwist(E, 24)); F[1..5] + %3 = [1, 0, 0, 72, 13822] + ? [E.disc, F.disc] + %4 = [-15763098924417024000, -82484842750] + @eprog\noindent For rational $j$, the following program returns the integral + curve of minimal discriminant and given $j$ invariant: + \bprog + ellfromjminimal(j)= + { my(E = ellinit(ellfromj(j))); + my(D = ellminimaltwist(E)); + + ellminimalmodel(elltwist(E,D)); + } + ? e = ellfromjminimal(1/2); e.disc + %1 = -82484842750 + @eprog Using $\fl = 1$ in \kbd{ellminimaltwist} would instead return the + curve of minimal conductor. For instance, if $j = 1728$, this would return a + different curve (of conductor $32$ instead of $64$). + +Function: ellgenerators +Class: basic +Section: elliptic_curves +C-Name: ellgenerators +Prototype: G +Help: ellgenerators(E): if E is an elliptic curve over the rationals, + return the generators of the Mordell-Weil group attached to the curve. + This relies on the curve being referenced in the elldata database. + If E is an elliptic curve over a finite field Fq as output by ellinit(), + return a minimal set of generators for the group E(Fq). +Doc: + If $E$ is an elliptic curve over the rationals, return a $\Z$-basis of the + free part of the \idx{Mordell-Weil group} attached to $E$. This relies on + the \tet{elldata} database being installed and referencing the curve, and so + is only available for curves over $\Z$ of small conductors. + If $E$ is an elliptic curve over a finite field $\F_{q}$ as output by + \tet{ellinit}, return a minimal set of generators for the group $E(\F_{q})$. + + \misctitle{Caution} When the group is not cyclic, of shape $\Z/d_{1}\Z \times + \Z/d_{2}\Z$ with $d_{2}\mid d_{1}$, the points $[P,Q]$ returned by + ellgenerators need not have order $d_{1}$ and $d_{2}$: it is true that + $P$ has order $d_{1}$, but we only know that $Q$ is a generator of + $E(\F_{q})/

$ and that the Weil pairing $w(P,Q)$ has order $d_{2}$, + see \kbd{??ellgroup}. + If you need generators $[P,R]$ with $R$ of order $d_{2}$, find + $x$ such that $R = Q-[x]P$ has order $d_{2}$ by solving + the discrete logarithm problem $[d_{2}]Q = [x]([d_{2}]P)$ in a cyclic group of + order $d_{1}/d_{2}$. This will be very expensive if $d_{1}/d_{2}$ has a large + prime factor. + +Function: ellglobalred +Class: basic +Section: elliptic_curves +C-Name: ellglobalred +Prototype: G +Help: ellglobalred(E): E being an elliptic curve over a number field, + returns [N, v, c, faN, L], where N is the conductor of E, + c is the product of the local Tamagawa numbers c_p, faN is the + factorization of N and L[i] is elllocalred(E, faN[i,1]); v is an obsolete + field. +Description: + (gen):gen ellglobalred($1) +Doc: let $E$ be an \kbd{ell} structure as output by \kbd{ellinit} attached + to an elliptic curve defined over a number field. This function calculates + the arithmetic conductor and the global \idx{Tamagawa number} $c$. + The result $[N,v,c,F,L]$ is slightly different if $E$ is defined + over $\Q$ (domain $D = 1$ in \kbd{ellinit}) or over a number field + (domain $D$ is a number field structure, including \kbd{nfinit(x)} + representing $\Q$ !): + + \item $N$ is the arithmetic conductor of the curve, + + \item $v$ is an obsolete field, left in place for backward compatibility. + If $E$ is defined over $\Q$, $v$ gives the coordinate change for $E$ to the + standard minimal integral model (\tet{ellminimalmodel} provides it in a + cheaper way); if $E$ is defined over another number field, $v$ gives a + coordinate change to an integral model (\tet{ellintegralmodel} provides it + in a cheaper way). + + \item $c$ is the product of the local Tamagawa numbers $c_{p}$, a quantity + which enters in the \idx{Birch and Swinnerton-Dyer conjecture}, + + \item $F$ is the factorization of $N$, + + \item $L$ is a vector, whose $i$-th entry contains the local data + at the $i$-th prime ideal divisor of $N$, i.e. + \kbd{L[i] = elllocalred(E,F[i,1])}. If $E$ is defined over $\Q$, the local + coordinate change has been deleted and replaced by a 0; if $E$ is defined + over another number field the local coordinate change to a local minimal + model is given relative to the integral model afforded by $v$ (so either + start from an integral model so that $v$ be trivial, or apply $v$ first). + +Function: ellgroup +Class: basic +Section: elliptic_curves +C-Name: ellgroup0 +Prototype: GDGD0,L, +Help: ellgroup(E,{p},{flag}): given an elliptic curve E defined over + a finite field Fq, returns the structure of the group E(Fq); for other fields + of definition K, p must define a finite residue field + (p prime for K = Qp or Q; p a maximal ideal for K a number field) and we + return the structure of the (nonsingular) reduction of E. + If flag is 1, also returns generators, but the curve equation must be minimal + at p. +Doc: + Let \kbd{E} be an \kbd{ell} structure as output by \kbd{ellinit}, attached + to an elliptic curve $E/K$. We first describe the function when the field + $K = \F_{q}$ is finite, it computes the structure of the finite abelian group + $E(\F_{q})$: + + \item if $\fl = 0$, returns the structure $[]$ (trivial group) or $[d_{1}]$ + (nontrivial cyclic group) or $[d_{1},d_{2}]$ (noncyclic group) of + $E(\F_{q}) \sim \Z/d_{1}\Z \times \Z/d_{2}\Z$, with $d_{2}\mid d_{1}$. + + \item if $\fl = 1$, returns a triple $[h,\var{cyc},\var{gen}]$, where + $h$ is the curve cardinality, \var{cyc} gives the group structure as a + product of cyclic groups (as per $\fl = 0$). More precisely, if $d_{2} > 1$, + the output is $[d_{1}d_{2}, [d_{1},d_{2}], [P,Q]]$ where $P$ is + of order $d_{1}$ and $[P,Q]$ generates the curve. + \misctitle{Caution} It is not guaranteed that $Q$ has order $d_{2}$, which in + the worst case requires an expensive discrete log computation. Only that + \kbd{ellweilpairing}$(E, P, Q, d_{1})$ has order $d_{2}$. + + For other fields of definition and $p$ defining a finite residue field + $\F_{q}$, returns the structure of the reduction of $E$: the argument + $p$ is best left omitted if $K = \Q_{\ell}$ (else we must have $p = \ell$) and + must be a prime number ($K = \Q$) or prime ideal ($K$ a general number field) + with residue field $\F_{q}$ otherwise. The curve is allowed to have bad + reduction at $p$ and in this case we consider the (cyclic) group of + nonsingular points for the reduction of a minimal model at $p$. + + If $\fl = 0$, the equation need not be minimal or even integral at $p$; of + course, a minimal model will be more efficient. + + If $\fl = 1$, the requested generators depend on the model, which must then + be minimal at $p$, otherwise an exception is thrown. Use + \kbd{ellintegralmodel} and/or \kbd{ellocalred} first to reduce to this case. + + \bprog + ? E = ellinit([0,1]); \\ y^2 = x^3 + 0.x + 1, defined over Q + ? ellgroup(E, 7) + %2 = [6, 2] \\ Z/6 x Z/2, noncyclic + ? E = ellinit([0,1] * Mod(1,11)); \\ defined over F_11 + ? ellgroup(E) \\ no need to repeat 11 + %4 = [12] + ? ellgroup(E, 11) \\ ... but it also works + %5 = [12] + ? ellgroup(E, 13) \\ ouch, inconsistent input! + *** at top-level: ellgroup(E,13) + *** ^-------------- + *** ellgroup: inconsistent moduli in Rg_to_Fp: + 11 + 13 + ? ellgroup(E, 7, 1) + %6 = [12, [6, 2], [[Mod(2, 7), Mod(4, 7)], [Mod(4, 7), Mod(4, 7)]]] + @eprog\noindent + Let us now consider curves of bad reduction, in this case we return the + structure of the (cyclic) group of nonsingular points, satisfying + $\#E_{ns}(\F_{p}) = p - a_{p}$: + \bprog + ? E = ellinit([0,5]); + ? ellgroup(E, 5, 1) + %2 = [5, [5], [[Mod(4, 5), Mod(2, 5)]]] + ? ellap(E, 5) + %3 = 0 \\ additive reduction at 5 + ? E = ellinit([0,-1,0,35,0]); + ? ellgroup(E, 5, 1) + %5 = [4, [4], [[Mod(2, 5), Mod(2, 5)]]] + ? ellap(E, 5) + %6 = 1 \\ split multiplicative reduction at 5 + ? ellgroup(E, 7, 1) + %7 = [8, [8], [[Mod(3, 7), Mod(5, 7)]]] + ? ellap(E, 7) + %8 = -1 \\ nonsplit multiplicative reduction at 7 + @eprog +Variant: Also available is \fun{GEN}{ellgroup}{GEN E, GEN p}, corresponding + to $\fl = 0$. + +Function: ellheegner +Class: basic +Section: elliptic_curves +C-Name: ellheegner +Prototype: G +Help: ellheegner(E): return a rational nontorsion point on the elliptic curve E + assumed to be of rank 1. +Doc: Let $E$ be an elliptic curve over the rationals, assumed to be of + (analytic) rank $1$. This returns a nontorsion rational point on the curve, + whose canonical height is equal to the product of the elliptic regulator by the + analytic Sha. + + This uses the Heegner point method, described in Cohen GTM 239; the complexity + is proportional to the product of the square root of the conductor and the + height of the point (thus, it is preferable to apply it to strong Weil curves). + \bprog + ? E = ellinit([-157^2,0]); + ? u = ellheegner(E); print(u[1], "\n", u[2]) + 69648970982596494254458225/166136231668185267540804 + 538962435089604615078004307258785218335/67716816556077455999228495435742408 + ? ellheegner(ellinit([0,1])) \\ E has rank 0 ! + *** at top-level: ellheegner(E=ellinit + *** ^-------------------- + *** ellheegner: The curve has even analytic rank. + @eprog + +Function: ellheight +Class: basic +Section: elliptic_curves +C-Name: ellheight0 +Prototype: GDGDGp +Help: ellheight(E,{P},{Q}): Faltings height of the curve E, resp. canonical + height of the point P on elliptic curve E, resp. the value of the attached + bilinear form at (P,Q). +Doc: Let $E$ be an elliptic curve defined over $K = \Q$ or a number field, + as output by \kbd{ellinit}; it needs not be given by a minimal model + although the computation will be faster if it is. + + \item Without arguments $P,Q$, returns the Faltings height of the curve $E$ + using Deligne normalization. For a rational curve, the normalization is such + that the function returns \kbd{-(1/2)*log(ellminimalmodel(E).area)}. + + \item If the argument $P \in E(K)$ is present, returns the global + N\'eron-Tate height $h(P)$ of the point, using the normalization in + Cremona's \emph{Algorithms for modular elliptic curves}. + + \item If the argument $Q \in E(K)$ is also present, computes the value of + the bilinear form $(h(P+Q)-h(P-Q)) / 4$. +Variant: Also available is \fun{GEN}{ellheight}{GEN E, GEN P, long prec} + ($Q$ omitted). + +Function: ellheightmatrix +Class: basic +Section: elliptic_curves +C-Name: ellheightmatrix +Prototype: GGp +Help: ellheightmatrix(E,x): gives the height matrix for vector of points x + on elliptic curve E. +Doc: $x$ being a vector of points, this + function outputs the Gram matrix of $x$ with respect to the N\'eron-Tate + height, in other words, the $(i,j)$ component of the matrix is equal to + \kbd{ellheight($E$,x[$i$],x[$j$])}. The rank of this matrix, at least in some + approximate sense, gives the rank of the set of points, and if $x$ is a + basis of the \idx{Mordell-Weil group} of $E$, its determinant is equal to + the regulator of $E$. Note our height normalization follows Cremona's + \emph{Algorithms for modular elliptic curves}: this matrix should be divided + by 2 to be in accordance with, e.g., Silverman's normalizations. + +Function: ellidentify +Class: basic +Section: elliptic_curves +C-Name: ellidentify +Prototype: G +Help: ellidentify(E): look up the elliptic curve E in the elldata database and + return [[N, M, ...], C] where N is the name of the curve in Cremona's + database, M the minimal model and C the change of coordinates (see + ellchangecurve). +Doc: look up the elliptic curve $E$, defined by an arbitrary model over $\Q$, + in the \tet{elldata} database. + Return \kbd{[[N, M, G], C]} where $N$ is the curve name in Cremona's + elliptic curve database, $M$ is the minimal model, $G$ is a $\Z$-basis of + the free part of the \idx{Mordell-Weil group} $E(\Q)$ and $C$ is the + change of coordinates from $E$ to $M$, suitable for \kbd{ellchangecurve}. + +Function: ellinit +Class: basic +Section: elliptic_curves +C-Name: ellinit +Prototype: GDGp +Help: ellinit(x,{D=1}): let x be a vector [a1,a2,a3,a4,a6], or [a4,a6] if + a1=a2=a3=0, defining the curve Y^2 + a1.XY + a3.Y = X^3 + a2.X^2 + a4.X + + a6; x can also be a string, in which case the curve with matching name is + retrieved from the elldata database, if available. This function initializes + an elliptic curve over the domain D (inferred from coefficients if omitted). +Description: + (gen, gen, small):ell:prec ellinit($1, $2, $prec) +Doc: + initialize an \tet{ell} structure, attached to the elliptic curve $E$. + $E$ is either + + \item a $5$-component vector $[a_{1},a_{2},a_{3},a_{4},a_{6}]$ defining the elliptic + curve with Weierstrass equation + $$ Y^{2} + a_{1} XY + a_{3} Y = X^{3} + a_{2} X^{2} + a_{4} X + a_{6}, $$ + + \item a $2$-component vector $[a_{4},a_{6}]$ defining the elliptic + curve with short Weierstrass equation + $$ Y^{2} = X^{3} + a_{4} X + a_{6}, $$ + + \item a single-component vector $[j]$ giving the $j$-invariant for the curve, + with the same coefficients as given by \kbd{ellfromj}. + + \item a character string in Cremona's notation, e.g. \kbd{"11a1"}, in which + case the curve is retrieved from the \tet{elldata} database if available. + + The optional argument $D$ describes the domain over which the curve is + defined: + + \item the \typ{INT} $1$ (default): the field of rational numbers $\Q$. + + \item a \typ{INT} $p$, where $p$ is a prime number: the prime finite field + $\F_{p}$. + + \item an \typ{INTMOD} \kbd{Mod(a, p)}, where $p$ is a prime number: the + prime finite field $\F_{p}$. + + \item a \typ{FFELT}, as returned by \tet{ffgen}: the corresponding finite + field $\F_{q}$. + + \item a \typ{PADIC}, $O(p^{n})$: the field $\Q_{p}$, where $p$-adic quantities + will be computed to a relative accuracy of $n$ digits. We advise to input a + model defined over $\Q$ for such curves. In any case, if you input an + approximate model with \typ{PADIC} coefficients, it will be replaced by a lift + to $\Q$ (an exact model ``close'' to the one that was input) and all quantities + will then be computed in terms of this lifted model, at the given accuracy. + + \item a \typ{REAL} $x$: the field $\C$ of complex numbers, where floating + point quantities are by default computed to a relative accuracy of + \kbd{precision}$(x)$. If no such argument is given, the value of + \kbd{realprecision} at the time \kbd{ellinit} is called will be used. + + \item a number field $K$, given by a \kbd{nf} or \kbd{bnf} structure; a + \kbd{bnf} is required for \kbd{ellminimalmodel}. + + \item a prime ideal $\goth{p}$, given by a \kbd{prid} structure; valid if + $x$ is a curve defined over a number field $K$ and the equation is integral + and minimal at $\goth{p}$. + + This argument $D$ is indicative: the curve coefficients are checked for + compatibility, possibly changing $D$; for instance if $D = 1$ and + an \typ{INTMOD} is found. If inconsistencies are detected, an error is + raised: + \bprog + ? ellinit([1 + O(5), 1], O(7)); + *** at top-level: ellinit([1+O(5),1],O + *** ^-------------------- + *** ellinit: inconsistent moduli in ellinit: 7 != 5 + @eprog\noindent If the curve coefficients are too general to fit any of the + above domain categories, only basic operations, such as point addition, will + be supported later. + + If the curve (seen over the domain $D$) is singular, fail and return an + empty vector $[]$. + \bprog + ? E = ellinit([0,0,0,0,1]); \\ y^2 = x^3 + 1, over Q + ? E = ellinit([0,1]); \\ the same curve, short form + ? E = ellinit("36a1"); \\ sill the same curve, Cremona's notations + ? E = ellinit([0]); \\ a curve of j-invariant 0 + ? E = ellinit([0,1], 2) \\ over F2: singular curve + %4 = [] + ? E = ellinit(['a4,'a6] * Mod(1,5)); \\ over F_5[a4,a6], basic support ! + @eprog\noindent Note that the given curve of $j$-invariant $0$ happens + to be \kbd{36a1} but a priori any model for an arbitrary twist could have + been returned. See \kbd{ellfromj}. + + The result of \tet{ellinit} is an \tev{ell} structure. It contains at least + the following information in its components: + % + $$ a_{1},a_{2},a_{3},a_{4},a_{6},b_{2},b_{4},b_{6},b_{8},c_{4},c_{6}, + \Delta,j.$$ + % + All are accessible via member functions. In particular, the discriminant is + \kbd{$E$.disc}, and the $j$-invariant is \kbd{$E$.j}. + \bprog + ? E = ellinit([a4, a6]); + ? E.disc + %2 = -64*a4^3 - 432*a6^2 + ? E.j + %3 = -6912*a4^3/(-4*a4^3 - 27*a6^2) + @eprog + Further components contain domain-specific data, which are in general dynamic: + only computed when needed, and then cached in the structure. + \bprog + ? E = ellinit([2,3], 10^60+7); \\ E over F_p, p large + ? ellap(E) + time = 4,440 ms. + %2 = -1376268269510579884904540406082 + ? ellcard(E); \\ now instantaneous ! + time = 0 ms. + ? ellgenerators(E); + time = 5,965 ms. + ? ellgenerators(E); \\ second time instantaneous + time = 0 ms. + @eprog + See the description of member functions related to elliptic curves at the + beginning of this section. + +Function: ellintegralmodel +Class: basic +Section: elliptic_curves +C-Name: ellintegralmodel +Prototype: GD& +Help: ellintegralmodel(E,{&v}): given an elliptic curve E defined + over a number field or Qp, returns an integral model. If v is present, + sets the variable v to the corresponding change of variable. +Doc: Let $E$ be an \kbd{ell} structure over a number field $K$ or $\Q_{p}$. + This function returns an integral model. If $v$ is present, sets + $v = [u,0,0,0]$ to the corresponding change of variable: the return value is + identical to that of \kbd{ellchangecurve(E, v)}. + \bprog + ? e = ellinit([1/17,1/42]); + ? e = ellintegralmodel(e,&v); + ? e[1..5] + %3 = [0, 0, 0, 15287762448, 3154568630095008] + ? v + %4 = [1/714, 0, 0, 0] + @eprog + +Function: elliscm +Class: basic +Section: elliptic_curves +C-Name: elliscm +Prototype: lG +Help: elliscm(E): return 0 if the elliptic curve E, defined + over a number field, is not CM, otherwise return the discriminant of its + endomorphism ring. +Doc: + Let $E$ an elliptic curve over a number field. + Return $0$ if $E$ is not CM, otherwise return the discriminant of its + endomorphism ring. + + \bprog + ? E = ellinit([0,0,-5,-750,7900]); + ? D = elliscm(E) + %2 = -27 + ? w = quadgen(D, 'w); + ? P = ellheegner(E) + %4 = [10,40] + ? Q = ellmul(E,P,w) + %5 = [110/7-5/49*w,85/49-225/343*w] + @eprog + + An example over a number field: + \bprog + ? nf=nfinit(a^2-5); + ? E = ellinit([261526980*a-584793000,-3440201839360*a+7692525148000],nf); + ? elliscm(E) + %3 = -20 + ? ellisomat(E)[2] + %4 = [1,2,5,10;2,1,10,5;5,10,1,2;10,5,2,1] + @eprog + +Function: ellisdivisible +Class: basic +Section: elliptic_curves +C-Name: ellisdivisible +Prototype: lGGGD& +Help: ellisdivisible(E,P,n,{&Q}): given E/K and P in E(K), + checks whether P = [n]R for some R in E(K) and sets Q to one such R if so; + the integer n >= 0 may be given as ellxn(E,n). +Doc: given $E/K$ a number field and $P$ in $E(K)$ + return $1$ if $P = [n]R$ for some $R$ in $E(K)$ and set $Q$ to one such $R$; + and return $0$ otherwise. + + \bprog + ? K = nfinit(polcyclo(11,t)); + ? E = ellinit([0,-1,1,0,0], K); + ? P = [0,0]; + ? ellorder(E,P) + %4 = 5 + ? ellisdivisible(E,P,5, &Q) + %5 = 1 + ? lift(Q) + %6 = [-t^7-t^6-t^5-t^4+1, -t^9-2*t^8-2*t^7-3*t^6-3*t^5-2*t^4-2*t^3-t^2-1] + ? ellorder(E, Q) + %7 = 25 + @eprog\noindent We use a fast multimodular algorithm over $\Q$ whose + complexity is essentially independent of $n$ (polynomial in $\log n$). + Over number fields, we compute roots of division polynomials and the + algebraic complexity of the underlying algorithm is in $O(p^{4})$, where $p$ is + the largest prime divisor of $n$. The integer $n \geq 0$ may be given as + \kbd{ellxn(E,n)}, if many points need to be tested; this provides a modest + speedup over number fields but is likely to slow down the algorithm over + $\Q$. + +Function: ellisisom +Class: basic +Section: elliptic_curves +C-Name: ellisisom +Prototype: GG +Help: ellisisom(E,F): return 0 if the elliptic curves E and F defined over the + same number field are not isomorphic, otherwise return [u,r,s,t] suitable for + ellchangecurve, mapping E to F. +Doc: + return $0$ if the elliptic curves $E$ and $F$ defined over the same number + field are not isomorphic, otherwise return \kbd{[u,r,s,t]} suitable for + \kbd{ellchangecurve}, mapping $E$ to $F$. + + \bprog + ? E = ellinit([1,2]); + ? ellisisom(E, ellinit([1,3])) + %2 = 0 + ? F = ellchangecurve(E, [-1,1,3,2]); + ? ellisisom(E,F) + %4 = [1, 1, -3, -2] + @eprog + + \bprog + ? nf = nfinit(a^3-2); E = ellinit([a^2+1,2*a-5], nf); + ? F = ellchangecurve(E,Mod([a, a+1, a^2, a^2+a-3], nf.pol)); + ? v = ellisisom(E,F) + %3 = [Mod(-a, a^3 - 2), Mod(a + 1, a^3 - 2), Mod(-a^2, a^3 - 2), + Mod(-a^2 - a + 3, a^3 - 2)] + ? ellchangecurve(E,v) == F + %4 = 1 + @eprog + +Function: ellisogeny +Class: basic +Section: elliptic_curves +C-Name: ellisogeny +Prototype: GGD0,L,DnDn +Help: ellisogeny(E,G,{only_image=0},{x='x},{y='y}): compute the image + and isogeny corresponding to the quotient of E by the subgroup G. +Doc: + Given an elliptic curve $E$, a finite subgroup $G$ of $E$ is given either + as a generating point $P$ (for a cyclic $G$) or as a polynomial whose roots + vanish on the $x$-coordinates of the nonzero elements of $G$ (general case + and more efficient if available). This function returns the + $[a_{1},a_{2},a_{3},a_{4},a_{6}]$ invariants of the quotient elliptic curve + $E/G$ and (if \var{only\_image} is zero (the default)) a vector of rational + functions $[f, g, h]$ such that the isogeny $E \to E/G$ is given by $(x,y) + \mapsto (f(x)/h(x)^{2}, g(x,y)/h(x)^{3})$. + \bprog + ? E = ellinit([0,1]); + ? elltors(E) + %2 = [6, [6], [[2, 3]]] + ? ellisogeny(E, [2,3], 1) \\ Weierstrass model for E/

+ %3 = [0, 0, 0, -135, -594] + ? ellisogeny(E,[-1,0]) + %4 = [[0,0,0,-15,22], [x^3+2*x^2+4*x+3, y*x^3+3*y*x^2-2*y, x+1]] + @eprog + +Function: ellisogenyapply +Class: basic +Section: elliptic_curves +C-Name: ellisogenyapply +Prototype: GG +Help: ellisogenyapply(f,g): given an isogeny f and g either a point P (in the + domain of f) or an isogeny, apply f to g: return the image of P under f or + the composite isogeny f o g. +Doc: + Given an isogeny of elliptic curves $f:E'\to E$ (being the result of a call + to \tet{ellisogeny}), apply $f$ to $g$: + + \item if $g$ is a point $P$ in the domain of $f$, return the image $f(P)$; + + \item if $g:E''\to E'$ is a compatible isogeny, return the composite + isogeny $f \circ g: E''\to E$. + + \bprog + ? one = ffgen(101, 't)^0; + ? E = ellinit([6, 53, 85, 32, 34] * one); + ? P = [84, 71] * one; + ? ellorder(E, P) + %4 = 5 + ? [F, f] = ellisogeny(E, P); \\ f: E->F = E/

+ ? ellisogenyapply(f, P) + %6 = [0] + ? F = ellinit(F); + ? Q = [89, 44] * one; + ? ellorder(F, Q) + %9 = 2 + ? [G, g] = ellisogeny(F, Q); \\ g: F->G = F/ + ? gof = ellisogenyapply(g, f); \\ gof: E -> G + @eprog + +Function: ellisomat +Class: basic +Section: elliptic_curves +C-Name: ellisomat +Prototype: GD0,L,D0,L, +Help: ellisomat(E,{p=0},{flag=0}): E being an elliptic curve over a number + field K, returns a list of representatives of the isomorphism classes of + elliptic curves defined over K and K-isogenous to E, with the corresponding + isogenies from E and their dual, and the matrix of the isogeny degrees between + the curves. If flag is 1, the isogenies are not computed, which saves + time. If p is set, it must be a prime number: in this case only isogenies of + degree a power of p are considered. +Doc: + Given an elliptic curve $E$ defined over a number field~$K$, computes + representatives of the set of isomorphism classes of elliptic curves defined + over~$K$ and $K$-isogenous to $E$, assuming it is finite (see below). + For any such curve $E_{i}$, let $f_{i}: E \to E_{i}$ be a rational isogeny + of minimal degree and let $g_{i}: E_{i} \to E$ be the dual isogeny; and let + $M$ be the matrix such that $M_{i,j}$ is the minimal degree for an isogeny + $E_{i} \to E_{j}$. + + The function returns a vector $[L,M]$ where $L$ is a list of triples + $[E_{i}, f_{i}, g_{i}]$ ($\fl = 0$), or simply the list of $E_{i}$ ($\fl = 1$, + which saves time). The curves $E_{i}$ are given in $[a_{4},a_{6}]$ form and + the first curve $E_{1}$ is isomorphic to $E$ by $f_{1}$. + + The set of isomorphism classes is finite except when $E$ has CM over a + quadratic order contained in $K$. In that case the function only returns the + discriminant of the quadratic order. + + If $p$ is set, it must be a prime number; in this which case only isogenies of + degree a power of $p$ are considered. + + Over a number field, the possible isogeny degrees are determined by + Billerey's algorithm. + + \bprog + ? E = ellinit("14a1"); + ? [L,M] = ellisomat(E); + ? LE = apply(x->x[1], L) \\ list of curves + %3 = [[215/48,-5291/864],[-675/16,6831/32],[-8185/48,-742643/864], + [-1705/48,-57707/864],[-13635/16,306207/32],[-131065/48,-47449331/864]] + ? L[2][2] \\ isogeny f_2 + %4 = [x^3+3/4*x^2+19/2*x-311/12, + 1/2*x^4+(y+1)*x^3+(y-4)*x^2+(-9*y+23)*x+(55*y+55/2),x+1/3] + ? L[2][3] \\ dual isogeny g_2 + %5 = [1/9*x^3-1/4*x^2-141/16*x+5613/64, + -1/18*x^4+(1/27*y-1/3)*x^3+(-1/12*y+87/16)*x^2+(49/16*y-48)*x + +(-3601/64*y+16947/512),x-3/4] + ? apply(E->ellidentify(ellinit(E))[1][1], LE) + %6 = ["14a1","14a4","14a3","14a2","14a6","14a5"] + ? M + %7 = + [1 3 3 2 6 6] + + [3 1 9 6 2 18] + + [3 9 1 6 18 2] + + [2 6 6 1 3 3] + + [6 2 18 3 1 9] + + [6 18 2 3 9 1] + @eprog + +Function: ellisoncurve +Class: basic +Section: elliptic_curves +C-Name: ellisoncurve +Prototype: GG +Help: ellisoncurve(E,z): true(1) if z is on elliptic curve E, false(0) if not. +Doc: gives 1 (i.e.~true) if the point $z$ is on the elliptic curve $E$, 0 + otherwise. If $E$ or $z$ have imprecise coefficients, an attempt is made to + take this into account, i.e.~an imprecise equality is checked, not a precise + one. It is allowed for $z$ to be a vector of points in which case a vector + (of the same type) is returned. +Variant: Also available is \fun{int}{oncurve}{GEN E, GEN z} which does not + accept vectors of points. + +Function: ellisotree +Class: basic +Section: elliptic_curves +C-Name: ellisotree +Prototype: G +Help: ellisotree(E): E being an elliptic curve over Q or a set of isogenous + rational curves as given by ellisomat, return minimal models of the isomorphism + classes of elliptic curves isogenous to E (or in the set) and the oriented + graph of isogenies of prime degree (adjacency matrix). +Doc: Given an elliptic curve $E$ defined over $\Q$ or a set of + $\Q$-isogenous curves as given by \kbd{ellisomat}, return a pair $[L,M]$ where + + \item $L$ lists the minimal models of the isomorphism classes of elliptic + curves $\Q$-isogenous to $E$ (or in the set of isogenous curves), + + \item $M$ is the adjacency matrix of the prime degree isogenies tree: + there is an edge from $E_{i}$ to $E_{j}$ if there is an isogeny $E_{i} \to + E_{j}$ of prime degree such that the N\'eron differential forms are + preserved. + + \bprog + ? E = ellinit("14a1"); + ? [L,M] = ellisotree(E); + ? M + %3 = + [0 0 3 2 0 0] + + [3 0 0 0 2 0] + + [0 0 0 0 0 2] + + [0 0 0 0 0 3] + + [0 0 0 3 0 0] + + [0 0 0 0 0 0] + ? [L2,M2] = ellisotree(ellisomat(E,2,1)); + %4 = + [0 2] + + [0 0] + ? [L3,M3] = ellisotree(ellisomat(E,3,1)); + ? M3 + %6 = + [0 0 3] + + [3 0 0] + + [0 0 0] + @eprog\noindent Compare with the result of \kbd{ellisomat}. + \bprog + ? [L,M]=ellisomat(E,,1); + ? M + %7 = + [1 3 3 2 6 6] + + [3 1 9 6 2 18] + + [3 9 1 6 18 2] + + [2 6 6 1 3 3] + + [6 2 18 3 1 9] + + [6 18 2 3 9 1] + @eprog + +Function: ellissupersingular +Class: basic +Section: elliptic_curves +C-Name: ellissupersingular +Prototype: iGDG +Help: ellissupersingular(E,{p}): return 1 if the elliptic curve E, defined + over a number field or a finite field, is supersingular at p, and 0 otherwise. +Doc: + Return 1 if the elliptic curve $E$ defined over a number field, $\Q_{p}$ + or a finite field is supersingular at $p$, and $0$ otherwise. + If the curve is defined over $\Q$ or a number field, $p$ must be explicitly + given, and must be a prime number, resp.~a maximal ideal; we return $1$ if and + only if $E$ has supersingular good reduction at $p$. + + Alternatively, $E$ can be given by its $j$-invariant in a finite field. In + this case $p$ must be omitted. + \bprog + ? g = ffprimroot(ffgen(7^5)) + %1 = 4*x^4+5*x^3+6*x^2+5*x+6 + ? [g^n | n <- [1 .. 7^5 - 1], ellissupersingular(g^n)] + %2 = [6] + ? j = ellsupersingularj(2^31-1) + %3 = 1618591527*w+1497042960 + ? ellissupersingular(j) + %4 = 1 + + ? K = nfinit(y^3-2); P = idealprimedec(K, 2)[1]; + ? E = ellinit([y,1], K); + ? ellissupersingular(E, P) + %7 = 1 + ? Q = idealprimedec(K,5)[1]; + ? ellissupersingular(E, Q) + %9 = 0 + @eprog +Variant: Also available is + \fun{int}{elljissupersingular}{GEN j} where $j$ is a $j$-invariant of a curve + over a finite field. + +Function: ellj +Class: basic +Section: elliptic_curves +C-Name: jell +Prototype: Gp +Help: ellj(x): elliptic j invariant of x. +Doc: + elliptic $j$-invariant. $x$ must be a complex number + with positive imaginary part, or convertible into a power series or a + $p$-adic number with positive valuation. + +Function: elllocalred +Class: basic +Section: elliptic_curves +C-Name: elllocalred +Prototype: GDG +Help: elllocalred(E,{p}): E being an elliptic curve, returns + [f,kod,[u,r,s,t],c], where f is the conductor's exponent, kod is the Kodaira + type for E at p, [u,r,s,t] is the change of variable needed to make E + minimal at p, and c is the local Tamagawa number c_p. +Doc: + calculates the \idx{Kodaira} type of the local fiber of the elliptic curve + $E$ at $p$. $E$ must be an \kbd{ell} structure as output by + \kbd{ellinit}, over $\Q_{\ell}$ ($p$ better left omitted, else equal to $\ell$) + over $\Q$ ($p$ a rational prime) or a number field $K$ ($p$ + a maximal ideal given by a \kbd{prid} structure). + The result is a 4-component vector $[f,kod,v,c]$. Here $f$ is the exponent of + $p$ in the arithmetic conductor of $E$, and $kod$ is the Kodaira type which + is coded as follows: + + 1 means good reduction (type I$_{0}$), 2, 3 and 4 mean types II, III and IV + respectively, $4+\nu$ with $\nu>0$ means type I$_{\nu}$; + finally the opposite values $-1$, $-2$, etc.~refer to the starred types + I$_{0}^{*}$, II$^{*}$, etc. The third component $v$ is itself a vector $[u,r,s,t]$ + giving the coordinate changes done during the local reduction; + $u = 1$ if and only if the given equation was already minimal at $p$. + Finally, the last component $c$ is the local \idx{Tamagawa number} $c_{p}$. + +Function: elllog +Class: basic +Section: elliptic_curves +C-Name: elllog +Prototype: GGGDG +Help: elllog(E,P,G,{o}): return the discrete logarithm of the point P of + the elliptic curve E in base G. If present, o represents the order of G. + If not present, assume that G generates the curve. +Doc: given two points $P$ and $G$ on the elliptic curve $E/\F_{q}$, returns the + discrete logarithm of $P$ in base $G$, i.e. the smallest nonnegative + integer $n$ such that $P = [n]G$. + See \tet{znlog} for the limitations of the underlying discrete log algorithms. + If present, $o$ represents the order of $G$, see \secref{se:DLfun}; + the preferred format for this parameter is \kbd{[N, factor(N)]}, where $N$ + is the order of $G$. + + If no $o$ is given, assume that $G$ generates the curve. + The function also assumes that $P$ is a multiple of $G$. + \bprog + ? a = ffgen(ffinit(2,8),'a); + ? E = ellinit([a,1,0,0,1]); \\ over F_{2^8} + ? x = a^3; y = ellordinate(E,x)[1]; + ? P = [x,y]; G = ellmul(E, P, 113); + ? ord = [242, factor(242)]; \\ P generates a group of order 242. Initialize. + ? ellorder(E, G, ord) + %4 = 242 + ? e = elllog(E, P, G, ord) + %5 = 15 + ? ellmul(E,G,e) == P + %6 = 1 + @eprog + +Function: elllseries +Class: basic +Section: elliptic_curves +C-Name: elllseries +Prototype: GGDGp +Obsolete: 2016-08-08 +Help: elllseries(E,s,{A=1}): L-series at s of the elliptic curve E, where A + a cut-off point close to 1. +Doc: + This function is deprecated, use \kbd{lfun(E,s)} instead. + + $E$ being an elliptic curve, given by an arbitrary model over $\Q$ as output + by \kbd{ellinit}, this function computes the value of the $L$-series of $E$ at + the (complex) point $s$. This function uses an $O(N^{1/2})$ algorithm, where + $N$ is the conductor. + + The optional parameter $A$ fixes a cutoff point for the integral and is best + left omitted; the result must be independent of $A$, up to + \kbd{realprecision}, so this allows to check the function's accuracy. + +Function: ellmaninconstant +Class: basic +Section: elliptic_curves +C-Name: ellmaninconstant +Prototype: G +Help: ellmaninconstant(E): let E be an elliptic curve over Q given by + ellinit or a rational isogeny class given by ellisomat. Return the + Manin constant of the curve, see ellweilcurve. + The algorithm is slow but unconditional. +Doc: let $E$ be an elliptic curve over $Q$ given by + \kbd{ellinit} or a rational isogeny class given by ellisomat. Return the + Manin constant of the curve, see \kbd{ellweilcurve}. + The algorithm is slow but unconditional. + The function also accepts the output of \kbd{ellisomat} and returns the list + of Manin constants for all the isogeny class. + \bprog + ? E = ellinit("11a3"); + ? ellmaninconstant(E) + %2 = 5 + ? L=ellisomat(E,,1); + ? ellmaninconstant(L) + %4 = [5,1,1] + @eprog + +Function: ellminimaldisc +Class: basic +Section: elliptic_curves +C-Name: ellminimaldisc +Prototype: G +Help: ellminimaldisc(E): E being an elliptic curve defined over a number + field output by ellinit, return the minimal discriminant ideal of E. +Doc: $E$ being an elliptic curve defined over a number field output by + \kbd{ellinit}, return the minimal discriminant ideal of E. + +Function: ellminimalmodel +Class: basic +Section: elliptic_curves +C-Name: ellminimalmodel +Prototype: GD& +Help: ellminimalmodel(E,{&v}): determines whether the elliptic curve E defined + over a number field admits a global minimal model. If so return it + and sets v to the corresponding change of variable. Else return the + (nonprincipal) Weierstrass class of E. +Doc: Let $E$ be an \kbd{ell} structure over a number field $K$. This function + determines whether $E$ admits a global minimal integral model. If so, it + returns it and sets $v = [u,r,s,t]$ to the corresponding change of variable: + the return value is identical to that of \kbd{ellchangecurve(E, v)}. + + Else return the (nonprincipal) Weierstrass class of $E$, i.e. the class of + $\prod \goth{p}^{(v_{\goth{p}}{\Delta} - \delta_{\goth{p}}) / 12}$ where + $\Delta = \kbd{E.disc}$ is the model's discriminant and + $\goth{p}^{\delta_{\goth{p}}}$ is the local minimal discriminant. + This function requires either that $E$ be defined + over the rational field $\Q$ (with domain $D = 1$ in \kbd{ellinit}), + in which case a global minimal model always exists, or over a number + field given by a \var{bnf} structure. The Weierstrass class is given in + \kbd{bnfisprincipal} format, i.e. in terms of the \kbd{K.gen} generators. + + The resulting model has integral coefficients and is everywhere minimal, the + coefficients $a_{1}$ and $a_{3}$ are reduced modulo $2$ (in terms of the fixed + integral basis \kbd{K.zk}) and $a_{2}$ is reduced modulo $3$. Over $\Q$, we + further require that $a_{1}$ and $a_{3}$ be $0$ or $1$, that $a_{2}$ + be $0$ or $\pm 1$ and that $u > 0$ in the change of variable: both the model + and the change of variable $v$ are then unique.\sidx{minimal model} + + \bprog + ? e = ellinit([6,6,12,55,233]); \\ over Q + ? E = ellminimalmodel(e, &v); + ? E[1..5] + %3 = [0, 0, 0, 1, 1] + ? v + %4 = [2, -5, -3, 9] + @eprog + + \bprog + ? K = bnfinit(a^2-65); \\ over a nonprincipal number field + ? K.cyc + %2 = [2] + ? u = Mod(8+a, K.pol); + ? E = ellinit([1,40*u+1,0,25*u^2,0], K); + ? ellminimalmodel(E) \\ no global minimal model exists over Z_K + %6 = [1]~ + @eprog + +Function: ellminimaltwist +Class: basic +Section: elliptic_curves +C-Name: ellminimaltwist0 +Prototype: GD0,L, +Help: ellminimaltwist(E,{flag=0}): E being an elliptic curve defined over Q, + return a discriminant D such that the twist of E by D is minimal among all + possible quadratic twists, i.e., if flag=0, its minimal model has minimal + discriminant, or if flag=1, it has minimal conductor. +Doc: Let $E$ be an elliptic curve defined over $\Q$, return + a discriminant $D$ such that the twist of $E$ by $D$ is minimal among all + possible quadratic twists, i.e. if $\fl=0$, its minimal model has minimal + discriminant, or if $\fl=1$, it has minimal conductor. + + In the example below, we find a curve with $j$-invariant $3$ and minimal + conductor. + \bprog + ? E = ellminimalmodel(ellinit(ellfromj(3))); + ? ellglobalred(E)[1] + %2 = 357075 + ? D = ellminimaltwist(E,1) + %3 = -15 + ? E2 = ellminimalmodel(elltwist(E,D)); + ? ellglobalred(E2)[1] + %5 = 14283 + @eprog + In the example below, $\fl=0$ and $\fl=1$ give different results. + \bprog + ? E = ellinit([1,0]); + ? D0 = ellminimaltwist(E,0) + %7 = 1 + ? D1 = ellminimaltwist(E,1) + %8 = 8 + ? E0 = ellminimalmodel(elltwist(E,D0)); + ? [E0.disc, ellglobalred(E0)[1]] + %10 = [-64, 64] + ? E1 = ellminimalmodel(elltwist(E,D1)); + ? [E1.disc, ellglobalred(E1)[1]] + %12 = [-4096, 32] + @eprog +Variant: Also available are + \fun{GEN}{ellminimaltwist}{E} for $\fl=0$, and + \fun{GEN}{ellminimaltwistcond}{E} for $\fl=1$. + +Function: ellmoddegree +Class: basic +Section: elliptic_curves +C-Name: ellmoddegree +Prototype: G +Help: ellmoddegree(e): e being an elliptic curve defined over Q output by + ellinit, compute the modular degree of e divided by the square of the + Manin constant. +Doc: $e$ being an elliptic curve defined over $\Q$ output by \kbd{ellinit}, + compute the modular degree of $e$ divided by the square of + the Manin constant $c$. It is conjectured that $c = 1$ for the strong Weil + curve in the isogeny class (optimal quotient of $J_{0}(N)$) and this can be + proven using \kbd{ellweilcurve} when the conductor $N$ is moderate. + \bprog + ? E = ellinit("11a1"); \\ from Cremona table: strong Weil curve and c = 1 + ? [v,smith] = ellweilcurve(E); smith \\ proof of the above + %2 = [[1, 1], [5, 1], [1, 1/5]] + ? ellmoddegree(E) + %3 = 1 + ? [ellidentify(e)[1][1] | e<-v] + %4 = ["11a1", "11a2", "11a3"] + ? ellmoddegree(ellinit("11a2")) + %5 = 5 + ? ellmoddegree(ellinit("11a3")) + %6 = 1/5 + @eprog\noindent The modular degree of \kbd{11a1} is $1$ (because + \kbd{ellweilcurve} or Cremona's table prove that the Manin constant + is $1$ for this curve); the output of \kbd{ellweilcurve} also proves + that the Manin constants of \kbd{11a2} and \kbd{11a3} are 1 and 5 + respectively, so the actual modular degree of both \kbd{11a2} and \kbd{11a3} + is 5. + +Function: ellmodulareqn +Class: basic +Section: elliptic_curves +C-Name: ellmodulareqn +Prototype: LDnDn +Help: ellmodulareqn(N,{x},{y}): given a prime N < 500, return a vector [P, t] + where P(x,y) is a modular equation of level N. This requires the package + seadata. The equation is either of canonical type (t=0) or of Atkin type (t=1). +Doc: given a prime $N < 500$, return a vector $[P,t]$ where $P(x,y)$ + is a modular equation of level $N$, i.e.~a bivariate polynomial with integer + coefficients; $t$ indicates the type of this equation: either + \emph{canonical} ($t = 0$) or \emph{Atkin} ($t = 1$). This function requires + the \kbd{seadata} package and its only use is to give access to the package + contents. See \tet{polmodular} for a more general and more flexible function. + + Let $j$ be the $j$-invariant function. The polynomial $P$ satisfies + the functional equation, + $$ P(f,j) = P(f \mid W_{N}, j \mid W_{N}) = 0 $$ + for some modular function $f = f_{N}$ (hand-picked for each fixed $N$ to + minimize its size, see below), where $W_{N}(\tau) = -1 / (N\*\tau)$ is the + Atkin-Lehner involution. These two equations allow to compute the values of + the classical modular polynomial $\Phi_{N}$, such that $\Phi_{N}(j(\tau), + j(N\tau)) = 0$, while being much smaller than the latter. More precisely, we + have $j(W_{N}(\tau)) = j(N\*\tau)$; the function $f$ is invariant under + $\Gamma_{0}(N)$ and also satisfies + + \item for Atkin type: $f \mid W_{N} = f$; + + \item for canonical type: let $s = 12/\gcd(12,N-1)$, then + $f \mid W_{N} = N^{s} / f$. In this case, $f$ has a simple definition: + $f(\tau) = N^{s} \* \big(\eta(N\*\tau) / \eta(\tau) \big)^{2\*s}$, + where $\eta$ is Dedekind's eta function. + + The following GP function returns values of the classical modular polynomial + by eliminating $f_{N}(\tau)$ in the above functional equation, + for $N\leq 31$ or $N\in\{41,47,59,71\}$. + + \bprog + classicaleqn(N, X='X, Y='Y)= + { + my([P,t] = ellmodulareqn(N), Q, d); + if (poldegree(P,'y) > 2, error("level unavailable in classicaleqn")); + if (t == 0, \\ Canonical + my(s = 12/gcd(12,N-1)); + Q = 'x^(N+1) * substvec(P,['x,'y],[N^s/'x,Y]); + d = N^(s*(2*N+1)) * (-1)^(N+1); + , \\ Atkin + Q = subst(P,'y,Y); + d = (X-Y)^(N+1)); + polresultant(subst(P,'y,X), Q) / d; + } + @eprog + +Function: ellmul +Class: basic +Section: elliptic_curves +C-Name: ellmul +Prototype: GGG +Help: ellmul(E,z,n): n times the point z on elliptic curve E (n in Z). +Doc: + computes $[n]z$, where $z$ is a point on the elliptic curve $E$. The + exponent $n$ is in $\Z$, or may be a complex quadratic integer if the curve $E$ + has complex multiplication by $n$ (if not, an error message is issued). + \bprog + ? Ei = ellinit([1,0]); z = [0,0]; + ? ellmul(Ei, z, 10) + %2 = [0] \\ unsurprising: z has order 2 + ? ellmul(Ei, z, I) + %3 = [0, 0] \\ Ei has complex multiplication by Z[i] + ? ellmul(Ei, z, quadgen(-4)) + %4 = [0, 0] \\ an alternative syntax for the same query + ? Ej = ellinit([0,1]); z = [-1,0]; + ? ellmul(Ej, z, I) + *** at top-level: ellmul(Ej,z,I) + *** ^-------------- + *** ellmul: not a complex multiplication in ellmul. + ? ellmul(Ej, z, 1+quadgen(-3)) + %6 = [1 - w, 0] + @eprog + The simple-minded algorithm for the CM case assumes that we are in + characteristic $0$, and that the quadratic order to which $n$ belongs has + small discriminant. + +Function: ellneg +Class: basic +Section: elliptic_curves +C-Name: ellneg +Prototype: GG +Help: ellneg(E,z): opposite of the point z on elliptic curve E. +Doc: + Opposite of the point $z$ on elliptic curve $E$. + +Function: ellnonsingularmultiple +Class: basic +Section: elliptic_curves +C-Name: ellnonsingularmultiple +Prototype: GG +Help: ellnonsingularmultiple(E,P): given E/Q and P in E(Q), returns the pair + [R,n] where n is the least positive integer such that R = [n]P has + everywhere good reduction. More precisely, its image in a minimal model + is everywhere nonsingular. +Doc: given an elliptic curve $E/\Q$ (more precisely, a model defined over $\Q$ + of a curve) and a rational point $P \in E(\Q)$, returns the pair $[R,n]$, + where $n$ is the least positive integer such that $R := [n]P$ has good + reduction at every prime. More precisely, its image in a minimal model is + everywhere nonsingular. + \bprog + ? e = ellinit("57a1"); P = [2,-2]; + ? ellnonsingularmultiple(e, P) + %2 = [[1, -1], 2] + ? e = ellinit("396b2"); P = [35, -198]; + ? [R,n] = ellnonsingularmultiple(e, P); + ? n + %5 = 12 + @eprog + +Function: ellorder +Class: basic +Section: elliptic_curves +C-Name: ellorder +Prototype: GGDG +Help: ellorder(E,z,{o}): order of the point z on the elliptic curve E over + a number field or a finite field, 0 if nontorsion. The parameter o, + if present, represents a nonzero multiple of the order of z. +Doc: gives the order of the point $z$ on the elliptic + curve $E$, defined over a finite field or a number field. + Return (the impossible value) zero if the point has infinite order. + \bprog + ? E = ellinit([-157^2,0]); \\ the "157-is-congruent" curve + ? P = [2,2]; ellorder(E, P) + %2 = 2 + ? P = ellheegner(E); ellorder(E, P) \\ infinite order + %3 = 0 + ? K = nfinit(polcyclo(11,t)); E=ellinit("11a3", K); T = elltors(E); + ? ellorder(E, T.gen[1]) + %5 = 25 + ? E = ellinit(ellfromj(ffgen(5^10))); + ? ellcard(E) + %7 = 9762580 + ? P = random(E); ellorder(E, P) + %8 = 4881290 + ? p = 2^160+7; E = ellinit([1,2], p); + ? N = ellcard(E) + %9 = 1461501637330902918203686560289225285992592471152 + ? o = [N, factor(N)]; + ? for(i=1,100, ellorder(E,random(E))) + time = 260 ms. + @eprog + The parameter $o$, is now mostly useless, and kept for backward + compatibility. If present, it represents a nonzero multiple of the order + of $z$, see \secref{se:DLfun}; the preferred format for this parameter is + \kbd{[ord, factor(ord)]}, where \kbd{ord} is the cardinality of the curve. + It is no longer needed since PARI is now able to compute it over large + finite fields (was restricted to small prime fields at the time this feature + was introduced), \emph{and} caches the result in $E$ so that it is computed + and factored only once. Modifying the last example, we see that including + this extra parameter provides no improvement: + \bprog + ? o = [N, factor(N)]; + ? for(i=1,100, ellorder(E,random(E),o)) + time = 260 ms. + @eprog +Variant: The obsolete form \fun{GEN}{orderell}{GEN e, GEN z} should no longer be + used. + +Function: ellordinate +Class: basic +Section: elliptic_curves +C-Name: ellordinate +Prototype: GGp +Help: ellordinate(E,x): y-coordinates corresponding to x-ordinate x on + elliptic curve E. +Doc: + gives a 0, 1 or 2-component vector containing + the $y$-coordinates of the points of the curve $E$ having $x$ as + $x$-coordinate. + +Function: ellpadicL +Class: basic +Section: elliptic_curves +C-Name: ellpadicL +Prototype: GGLDGD0,L,DG +Help: ellpadicL(E,p,n,{s=0},{r=0},{D=1}): returns the value + on a character of Z_{p}^* represented by an integer s or a vector [s1,s2] + of the derivative of order r of the p-adic L-function of + the elliptic curve E (twisted by D, if present). +Doc: Returns the value (or $r$-th derivative) on a character $\chi^{s}$ of + $\Z_{p}^{*}$ of the $p$-adic $L$-function of the elliptic curve $E/\Q$, twisted by + $D$, given modulo $p^{n}$. + + \misctitle{Characters} The set of continuous characters of + $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$ is identified to $\Z_{p}^{*}$ via the + cyclotomic character $\chi$ with values in $\overline{\Q_{p}}^{*}$. Denote by + $\tau:\Z_{p}^{*}\to\Z_{p}^{*}$ the Teichm\"uller character, with values + in the $(p-1)$-th roots of $1$ for $p\neq 2$, and $\{-1,1\}$ for $p = 2$; + finally, let + $\langle\chi\rangle =\chi \tau^{-1}$, with values in $1 + 2p\Z_{p}$. + In GP, the continuous character of + $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$ given by $\langle\chi\rangle^{s_{1}} + \tau^{s_{2}}$ is represented by the pair of integers $s=(s_{1},s_{2})$, + with $s_{1} \in \Z_{p}$ and $s_{2} \bmod p-1$ for $p > 2$, + (resp. mod $2$ for $p = 2$); $s$ + may be also an integer, representing $(s,s)$ or $\chi^{s}$. + + \misctitle{The $p$-adic $L$ function} + The $p$-adic $L$ function $L_{p}$ is defined on the set of continuous + characters of $\text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$, as $\int_{\Z_{p}^{*}} + \chi^{s} d \mu$ for a certain $p$-adic distribution $\mu$ on $\Z_{p}^{*}$. The + derivative is given by + $$L_{p}^{(r)}(E, \chi^{s}) = \int_{\Z_{p}^{*}} \log_{p}^{r}(a) \chi^{s}(a) + d\mu(a).$$ + More precisely: + + \item When $E$ has good supersingular reduction, $L_{p}$ takes its + values in $D := H^{1}_{dR}(E/\Q)\otimes_{\Q} \Q_{p}$ and satisfies + $$(1-p^{-1} F)^{-2} L_{p}(E, \chi^{0})= (L(E,1) / \Omega) \cdot \omega$$ + where $F$ is the Frobenius, $L(E,1)$ is the value of the complex $L$ + function at $1$, $\omega$ is the N\'eron differential + and $\Omega$ the attached period on $E(\R)$. Here, $\chi^{0}$ represents + the trivial character. + + The function returns the components of $L_{p}^{(r)}(E,\chi^{s})$ in + the basis $(\omega, F \omega)$. + + \item When $E$ has ordinary good reduction, this method only defines + the projection of $L_{p}(E,\chi^{s})$ on the $\alpha$-eigenspace, + where $\alpha$ is the unit eigenvalue for $F$. This is what the function + returns. We have + $$(1- \alpha^{-1})^{-2} L_{p,\alpha}(E,\chi^{0})= L(E,1) / \Omega.$$ + + Two supersingular examples: + \bprog + ? cxL(e) = bestappr( ellL1(e) / e.omega[1] ); + + ? e = ellinit("17a1"); p=3; \\ supersingular, a3 = 0 + ? L = ellpadicL(e,p,4); + ? F = [0,-p;1,ellap(e,p)]; \\ Frobenius matrix in the basis (omega,F(omega)) + ? (1-p^(-1)*F)^-2 * L / cxL(e) + %5 = [1 + O(3^5), O(3^5)]~ \\ [1,0]~ + + ? e = ellinit("116a1"); p=3; \\ supersingular, a3 != 0~ + ? L = ellpadicL(e,p,4); + ? F = [0,-p; 1,ellap(e,p)]; + ? (1-p^(-1)*F)^-2*L~ / cxL(e) + %9 = [1 + O(3^4), O(3^5)]~ + @eprog + + Good ordinary reduction: + \bprog + ? e = ellinit("17a1"); p=5; ap = ellap(e,p) + %1 = -2 \\ ordinary + ? L = ellpadicL(e,p,4) + %2 = 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^4) + ? al = padicappr(x^2 - ap*x + p, ap + O(p^7))[1]; + ? (1-al^(-1))^(-2) * L / cxL(e) + %4 = 1 + O(5^4) + @eprog + + Twist and Teichm\"uller: + \bprog + ? e = ellinit("17a1"); p=5; \\ ordinary + \\ 2nd derivative at tau^1, twist by -7 + ? ellpadicL(e, p, 4, [0,1], 2, -7) + %2 = 2*5^2 + 5^3 + O(5^4) + @eprog + We give an example of non split multiplicative reduction (see + \tet{ellpadicbsd} for more examples). + \bprog + ? e=ellinit("15a1"); p=3; n=5; + ? L = ellpadicL(e,p,n) + %2 = 2 + 3 + 3^2 + 3^3 + 3^4 + O(3^5) + ? (1 - ellap(e,p))^(-1) * L / cxL(e) + %3 = 1 + O(3^5) + @eprog + + This function is a special case of \tet{mspadicL} and it also appears + as the first term of \tet{mspadicseries}: + \bprog + ? e = ellinit("17a1"); p=5; + ? L = ellpadicL(e,p,4) + %2 = 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^4) + ? [M,phi] = msfromell(e, 1); + ? Mp = mspadicinit(M, p, 4); + ? mu = mspadicmoments(Mp, phi); + ? mspadicL(mu) + %6 = 4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + O(5^6) + ? mspadicseries(mu) + %7 = (4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + O(5^6)) + + (3 + 3*5 + 5^2 + 5^3 + O(5^4))*x + + (2 + 3*5 + 5^2 + O(5^3))*x^2 + + (3 + 4*5 + 4*5^2 + O(5^3))*x^3 + + (3 + 2*5 + O(5^2))*x^4 + O(x^5) + @eprog\noindent These are more cumbersome than \kbd{ellpadicL} but allow to + compute at different characters, or successive derivatives, or to + twist by a quadratic character essentially for the cost of a single call to + \kbd{ellpadicL} due to precomputations. + +Function: ellpadicbsd +Class: basic +Section: elliptic_curves +C-Name: ellpadicbsd +Prototype: GGLDG +Help: ellpadicbsd(E,p,n,{D=1}): returns [r,Lp] where + r is the (conjectural) analytic rank of the p-adic L-function attached + to the quadratic twist E_D and Lp is (conjecturally) equal + to the product of the p-adic regulator and the cardinal of the + Tate-Shafarevich group. +Doc: Given an elliptic curve $E$ over $\Q$, its quadratic twist $E_{D}$ + and a prime number $p$, this function is a $p$-adic analog of the complex + functions \tet{ellanalyticrank} and \tet{ellbsd}. It calls \kbd{ellpadicL} + with initial accuracy $p^{n}$ and may increase it internally; + it returns a vector $[r, L_{p}]$ where + + \item $L_{p}$ is a $p$-adic number (resp. a pair of $p$-adic numbers if + $E$ has good supersingular reduction) defined modulo $p^{N}$, conjecturally + equal to $R_{p} S$, where $R_{p}$ is the $p$-adic regulator as given by + \tet{ellpadicregulator} (in the basis $(\omega, F \omega)$) and $S$ is the + cardinal of the Tate-Shafarevich group for the quadratic twist $E_{D}$. + + \item $r$ is an upper bound for the analytic rank of the $p$-adic + $L$-function attached to $E_{D}$: we know for sure that the $i$-th + derivative of $L_{p}(E_{D},.)$ at $\chi^{0}$ is $O(p^{N})$ for all $i < r$ + and that its $r$-th derivative is nonzero; it is expected that the true + analytic rank is equal to the rank of the Mordell-Weil group $E_{D}(\Q)$, + plus $1$ if the reduction of $E_{D}$ at $p$ is split multiplicative; + if $r = 0$, then both the analytic rank and the Mordell-Weil rank are + unconditionnally $0$. + + Recall that the $p$-adic BSD conjecture (Mazur, Tate, Teitelbaum, Bernardi, + Perrin-Riou) predicts an explicit link between $R_{p} S$ and + $$(1-p^{-1} F)^{-2} \cdot L_{p}^{(r)}(E_{D}, \chi^{0}) / r! $$ + where $r$ is the analytic rank of the $p$-adic $L$-function attached to + $E_{D}$ and $F$ is the Frobenius on $H^{1}_{dR}$; see \tet{ellpadicL} + for definitions. + \bprog + ? E = ellinit("11a1"); p = 7; n = 5; \\ good ordinary + ? ellpadicbsd(E, 7, 5) \\ rank 0, + %2 = [0, 1 + O(7^5)] + + ? E = ellinit("91a1"); p = 7; n = 5; \\ non split multiplicative + ? [r,Lp] = ellpadicbsd(E, p, n) + %5 = [1, 2*7 + 6*7^2 + 3*7^3 + 7^4 + O(7^5)] + ? R = ellpadicregulator(E, p, n, E.gen) + %6 = 2*7 + 6*7^2 + 3*7^3 + 7^4 + 5*7^5 + O(7^6) + ? sha = Lp/R + %7 = 1 + O(7^4) + + ? E = ellinit("91b1"); p = 7; n = 5; \\ split multiplicative + ? [r,Lp] = ellpadicbsd(E, p, n) + %9 = [2, 2*7 + 7^2 + 5*7^3 + O(7^4)] + ? ellpadicregulator(E, p, n, E.gen) + %10 = 2*7 + 7^2 + 5*7^3 + 6*7^4 + 2*7^5 + O(7^6) + ? [rC, LC] = ellanalyticrank(E); + ? [r, rC] + %12 = [2, 1] \\ r = rC+1 because of split multiplicative reduction + + ? E = ellinit("53a1"); p = 5; n = 5; \\ supersingular + ? [r, Lp] = ellpadicbsd(E, p, n); + ? r + %15 = 1 + ? Lp + %16 = [3*5 + 2*5^2 + 2*5^5 + O(5^6), \ + 5 + 3*5^2 + 4*5^3 + 2*5^4 + 5^5 + O(5^6)] + ? R = ellpadicregulator(E, p, n, E.gen) + %17 = [3*5 + 2*5^2 + 2*5^5 + O(5^6), 5 + 3*5^2 + 4*5^3 + 2*5^4 + O(5^5)] + \\ expect Lp = R*#Sha, hence (conjecturally) #Sha = 1 + + ? E = ellinit("84a1"); p = 11; n = 6; D = -443; + ? [r,Lp] = ellpadicbsd(E, 11, 6, D) \\ Mordell-Weil rank 0, no regulator + %19 = [0, 3 + 2*11 + O(11^6)] + ? lift(Lp) \\ expected cardinal for Sha is 5^2 + %20 = 25 + ? ellpadicbsd(E, 3, 12, D) \\ at 3 + %21 = [1, 1 + 2*3 + 2*3^2 + O(3^8)] + ? ellpadicbsd(E, 7, 8, D) \\ and at 7 + %22 = [0, 4 + 3*7 + O(7^8)] + @eprog + +Function: ellpadicfrobenius +Class: basic +Section: elliptic_curves +C-Name: ellpadicfrobenius +Prototype: GUL +Help: ellpadicfrobenius(E,p,n): matrix of the Frobenius at p>2 in the standard + basis of H^1_dR(E) to absolute p-adic precision p^n. +Doc: If $p>2$ is a prime and $E$ is an elliptic curve on $\Q$ with good + reduction at $p$, return the matrix of the Frobenius endomorphism $\varphi$ + on the crystalline module $D_{p}(E)= \Q_{p} \otimes H^{1}_{dR}(E/\Q)$ with + respect to the basis of the given model $(\omega, \eta=x\*\omega)$, where + $\omega = dx/(2\*y+a_{1}\*x+a_{3})$ is the invariant differential. + The characteristic polynomial of $\varphi$ is $x^{2} - a_{p}\*x + p$. + The matrix is computed to absolute $p$-adic precision $p^{n}$. + + \bprog + ? E = ellinit([1,-1,1,0,0]); + ? F = ellpadicfrobenius(E,5,3); + ? lift(F) + %3 = + [120 29] + + [ 55 5] + ? charpoly(F) + %4 = x^2 + O(5^3)*x + (5 + O(5^3)) + ? ellap(E, 5) + %5 = 0 + @eprog + +Function: ellpadicheight +Class: basic +Section: elliptic_curves +C-Name: ellpadicheight0 +Prototype: GGLGDG +Help: ellpadicheight(E,p,n,P,{Q}): E elliptic curve/Q, P in E(Q), + p prime, n an integer; returns the cyclotomic p-adic heights of P. + Resp. the value of the attached bilinear form at (P,Q). +Doc: cyclotomic $p$-adic height of the rational point $P$ on the elliptic curve + $E$ (defined over $\Q$), given to $n$ $p$-adic digits. + If the argument $Q$ is present, computes the value of the bilinear + form $(h(P+Q)-h(P-Q)) / 4$. + + Let $D := H^{1}_{dR}(E) \otimes_{\Q} \Q_{p}$ be the $\Q_{p}$ vector space + spanned by $\omega$ + (invariant differential $dx/(2y+a_{1}x+a_{3})$ related to the given model) and + $\eta = x \omega$. Then the cyclotomic $p$-adic height $h_{E}$ associates to + $P\in E(\Q)$ an element $f \omega + g \eta$ in $D$. + This routine returns the vector $[f, g]$ to $n$ $p$-adic digits. + If $P\in E(\Q)$ is in the kernel of reduction mod $p$ and if its reduction + at all finite places is non singular, then $g = -(\log_{E} P)^{2}$, where + $\log_{E}$ is the logarithm for the formal group of $E$ at $p$. + + If furthermore the model is of the form $Y^{2} = X^{3} + a X + b$ + and $P = (x,y)$, then + $$ f = \log_{p}(\kbd{denominator}(x)) - 2 \log_{p}(\sigma(P))$$ + where $\sigma(P)$ is given by \kbd{ellsigma}$(E,P)$. + + Recall (\emph{Advanced topics in the arithmetic of elliptic + curves}, Theorem~3.2) that the local height function over the complex numbers + is of the form + $$ \lambda(z) = -\log (|\kbd{E.disc}|) / 6 + \Re(z \eta(z)) - 2 \log( + \sigma(z)). $$ + (N.B. our normalization for local and global heights is twice that of + Silverman's). + \bprog + ? E = ellinit([1,-1,1,0,0]); P = [0,0]; + ? ellpadicheight(E,5,3, P) + %2 = [3*5 + 5^2 + 2*5^3 + O(5^4), 5^2 + 4*5^4 + O(5^5)] + ? E = ellinit("11a1"); P = [5,5]; \\ torsion point + ? ellpadicheight(E,19,6, P) + %4 = [0, 0] + ? E = ellinit([0,0,1,-4,2]); P = [-2,1]; + ? ellpadicheight(E,3,3, P) + %6 = [2*3^2 + 2*3^3 + 3^4 + O(3^5), 2*3^2 + 3^4 + O(3^5)] + ? ellpadicheight(E,3,5, P, elladd(E,P,P)) + %7 = [3^2 + 2*3^3 + O(3^7), 3^2 + 3^3 + 2*3^4 + 3^5 + O(3^7)] + @eprog + + \item When $E$ has good ordinary reduction at $p$ or non split multiplicative + reduction, the ``canonical'' $p$-adic height is given by + \bprog + s2 = ellpadics2(E,p,n); + ellpadicheight(E, p, n, P) * [1,-s2]~ + @eprog\noindent Since $s_{2}$ does not depend on $P$, it is preferable to + compute it only once: + \bprog + ? E = ellinit("5077a1"); p = 5; n = 7; \\ rank 3 + ? s2 = ellpadics2(E,p,n); + ? M = ellpadicheightmatrix(E,p, n, E.gen) * [1,-s2]~; + ? matdet(M) \\ p-adic regulator on the points in E.gen + %4 = 5 + 5^2 + 4*5^3 + 2*5^4 + 2*5^5 + 2*5^6 + O(5^7) + @eprog + + \item When $E$ has split multiplicative reduction at $p$ (Tate curve), + the ``canonical'' $p$-adic height is given by + \bprog + Ep = ellinit(E[1..5], O(p^(n))); \\ E seen as a Tate curve over Qp + [u2,u,q] = Ep.tate; + ellpadicheight(E, p, n, P) * [1,-s2 + 1/log(q)/u2]]~ + @eprog\noindent where $s_{2}$ is as above. For example, + \bprog + ? E = ellinit("91b1"); P =[-1, 3]; p = 7; n = 5; + ? Ep = ellinit(E[1..5], O(p^(n))); + ? s2 = ellpadics2(E,p,n); + ? [u2,u,q] = Ep.tate; + ? H = ellpadicheight(E,p, n, P) * [1,-s2 + 1/log(q)/u2]~ + %5 = 2*7 + 7^2 + 5*7^3 + 6*7^4 + 2*7^5 + O(7^6) + @eprog These normalizations are chosen so that $p$-adic BSD conjectures + are easy to state, see \tet{ellpadicbsd}. + +Function: ellpadicheightmatrix +Class: basic +Section: elliptic_curves +C-Name: ellpadicheightmatrix +Prototype: GGLG +Help: ellpadicheightmatrix(E,p,n,Q): gives the height-pairing matrix for vector + of points Q on elliptic curve E. +Doc: $Q$ being a vector of points, this function returns the ``Gram matrix'' + $[F,G]$ of the cyclotomic $p$-adic height $h_{E}$ with respect to + the basis $(\omega, \eta)$ of $D=H^{1}_{dR}(E) \otimes_{\Q} \Q_{p}$ + given to $n$ $p$-adic digits. In other words, if + \kbd{ellpadicheight}$(E,p,n, Q[i],Q[j]) = [f,g]$, corresponding to + $f \omega + g \eta$ in $D$, then $F[i,j] = f$ and $G[i,j] = g$. + \bprog + ? E = ellinit([0,0,1,-7,6]); Q = [[-2,3],[-1,3]]; p = 5; n = 5; + ? [F,G] = ellpadicheightmatrix(E,p,n,Q); + ? lift(F) \\ p-adic entries, integral approximation for readability + %3 = + [2364 3100] + + [3100 3119] + + ? G + %4 = + [25225 46975] + + [46975 61850] + + ? [F,G] * [1,-ellpadics2(E,p,n)]~ + %5 = + [4 + 2*5 + 4*5^2 + 3*5^3 + O(5^5) 4*5^2 + 4*5^3 + 5^4 + O(5^5)] + + [ 4*5^2 + 4*5^3 + 5^4 + O(5^5) 4 + 3*5 + 4*5^2 + 4*5^3 + 5^4 + O(5^5)] + + @eprog + +Function: ellpadiclambdamu +Class: basic +Section: elliptic_curves +C-Name: ellpadiclambdamu +Prototype: GLD1,L,D0,L, +Help: ellpadiclambdamu(E,p,{D=1},{i=0}): returns the Iwasawa invariants for + the p-adic L-function attached to E, twisted by (D,.) and the i-th power + of the Teichmuller character. +Doc: Let $p$ be a prime number and let $E/\Q$ be a rational elliptic curve + with good or bad multiplicative reduction at $p$. + Return the Iwasawa invariants $\lambda$ and $\mu$ for the $p$-adic $L$ + function $L_{p}(E)$, twisted by $(D/.)$ and the $i$-th power of the + Teichm\"uller character $\tau$, see \kbd{ellpadicL} for details about + $L_{p}(E)$. + + Let $\chi$ be the cyclotomic character and choose $\gamma$ + in $\text{Gal}(\Q_{p}(\mu_{p^{\infty}})/\Q_{p})$ such that $\chi(\gamma)=1+2p$. + Let $\hat{L}^{(i), D} \in \Q_{p}[[X]]\otimes D_{cris}$ such that + $$ (<\chi>^{s} \tau^{i}) (\hat{L}^{(i), D}(\gamma-1)) + = L_{p}\big(E, <\chi>^{s}\tau^{i} (D/.)\big).$$ + + \item When $E$ has good ordinary or bad multiplicative reduction at $p$. + By Weierstrass's preparation theorem the series $\hat{L}^{(i), D}$ can be + written $p^{\mu} (X^{\lambda} + p G(X))$ up to a $p$-adic unit, where + $G(X)\in \Z_{p}[X]$. The function returns $[\lambda,\mu]$. + + \item When $E$ has good supersingular reduction, we define a sequence + of polynomials $P_{n}$ in $\Q_{p}[X]$ of degree $< p^{n}$ (and bounded + denominators), such that + $$\hat{L}^{(i), D} \equiv P_{n} \varphi^{n+1}\omega_{E} - + \xi_{n} P_{n-1}\varphi^{n+2}\omega_{E} \bmod \big((1+X)^{p^{n}}-1\big) + \Q_{p}[X]\otimes D_{cris},$$ + where $\xi_{n} = \kbd{polcyclo}(p^{n}, 1+X)$. + Let $\lambda_{n},\mu_{n}$ be the invariants of $P_{n}$. We find that + + \item $\mu_{n}$ is nonnegative and decreasing for $n$ of given parity hence + $\mu_{2n}$ tends to a limit $\mu^{+}$ and $\mu_{2n+1}$ tends to a limit + $\mu^{-}$ (both conjecturally $0$). + + \item there exists integers $\lambda^{+}$, $\lambda^{-}$ + in $\Z$ (denoted with a $\til$ in the reference below) such that + $$ \lim_{n\to\infty} \lambda_{2n} + 1/(p+1) = \lambda^{+} + \quad \text{and} \quad + \lim_{n\to\infty} \lambda_{2n+1} + p/(p+1) = \lambda^{-}.$$ + The function returns $[[\lambda^{+}, \lambda^{-}], [\mu^{+},\mu^{-}]]$. + + \noindent Reference: B. Perrin-Riou, Arithm\'etique des courbes elliptiques + \`a r\'eduction supersinguli\`ere en $p$, \emph{Experimental Mathematics}, + {\bf 12}, 2003, pp. 155-186. + +Function: ellpadiclog +Class: basic +Section: elliptic_curves +C-Name: ellpadiclog +Prototype: GGLG +Help: ellpadiclog(E,p,n,P): returns the logarithm of P (in the kernel of + reduction) to relative p-adic precision p^n. +Doc: Given $E$ defined over $K = \Q$ or $\Q_{p}$ and $P = [x,y]$ on $E(K)$ in the + kernel of reduction mod $p$, let $t(P) = -x/y$ be the formal group + parameter; this function returns $L(t)$ to relative $p$-adic precision + $p^{n}$, where $L$ denotes the formal logarithm (mapping the formal group + of $E$ to the additive formal group) attached to the canonical invariant + differential: $dL = dx/(2y + a_{1}x + a_{3})$. + \bprog + ? E = ellinit([0,0,1,-4,2]); P = [-2,1]; + ? ellpadiclog(E,2,10,P) + %2 = 2 + 2^3 + 2^8 + 2^9 + 2^10 + O(2^11) + ? E = ellinit([17,42]); + ? p=3; Ep = ellinit(E,p); \\ E mod p + ? P=[114,1218]; ellorder(Ep,P) \\ the order of P on (E mod p) is 2 + %5 = 2 + ? Q = ellmul(E,P,2) \\ we need a point of the form 2*P + %6 = [200257/7056, 90637343/592704] + ? ellpadiclog(E,3,10,Q) + %7 = 3 + 2*3^2 + 3^3 + 3^4 + 3^5 + 3^6 + 2*3^8 + 3^9 + 2*3^10 + O(3^11) + @eprog + +Function: ellpadicregulator +Class: basic +Section: elliptic_curves +C-Name: ellpadicregulator +Prototype: GGLG +Help: ellpadicregulator(E,p,n,S): E elliptic curve/Q, S a vector of + points in E(Q), p prime, n an integer; returns the p-adic + cyclotomic regulator of the points of S at precision p^n. +Doc: Let $E/\Q$ be an elliptic curve. Return the determinant of the Gram + matrix of the vector of points $S=(S_{1},\cdots, S_{r})$ with respect to the + ``canonical'' cyclotomic $p$-adic height on $E$, given to $n$ ($p$-adic) + digits. + + When $E$ has ordinary reduction at $p$, this is the expected Gram + deteterminant in $\Q_{p}$. + + In the case of supersingular reduction of $E$ at $p$, the definition + requires care: the regulator $R$ is an element of + $D := H^{1}_{dR}(E) \otimes_{\Q} \Q_{p}$, which is a two-dimensional + $\Q_{p}$-vector space spanned by $\omega$ and $\eta = x \omega$ + (which are defined over $\Q$) or equivalently but now over $\Q_{p}$ + by $\omega$ and $F\omega$ where $F$ is the Frobenius endomorphism on $D$ + as defined in \kbd{ellpadicfrobenius}. On $D$ we + define the cyclotomic height $h_{E} = f \omega + g \eta$ + (see \tet{ellpadicheight}) and a canonical alternating bilinear form + $[.,.]_{D}$ such that $[\omega, \eta]_{D} = 1$. + + For any $\nu \in D$, we can define a height $h_{\nu} := [ h_{E}, \nu ]_{D}$ + from $E(\Q)$ to $\Q_{p}$ and $\langle \cdot, \cdot \rangle_{\nu}$ the attached + bilinear form. In particular, if $h_{E} = f \omega + g\eta$, then + $h_{\eta} = [ h_{E}, \eta ]_{D}$ = f and $h_{\omega} = [ h_{E}, \omega ]_{D} + = - g$ hence $h_{E} = h_{\eta} \omega - h_{\omega} \eta$. + Then, $R$ is the unique element of $D$ such that + $$[\omega,\nu]_{D}^{r-1} [R, \nu]_{D} = \det(\langle S_{i}, S_{j} \rangle_{\nu})$$ + for all $\nu \in D$ not in $\Q_{p} \omega$. The \kbd{ellpadicregulator} + function returns $R$ in the basis $(\omega, F\omega)$, which was chosen + so that $p$-adic BSD conjectures are easy to state, see \kbd{ellpadicbsd}. + + Note that by definition + $$[R, \eta]_{D} = \det(\langle S_{i}, S_{j} \rangle_{\eta})$$ + and + $$[R, \omega+\eta]_{D} =\det(\langle S_{i}, S_{j} \rangle_{\omega+\eta}).$$ + +Function: ellpadics2 +Class: basic +Section: elliptic_curves +C-Name: ellpadics2 +Prototype: GGL +Help: ellpadics2(E,p,n): returns s2 to absolute p-adic precision p^n. +Doc: If $p>2$ is a prime and $E/\Q$ is an elliptic curve with ordinary good + reduction at $p$, returns the slope of the unit eigenvector + of \kbd{ellpadicfrobenius(E,p,n)}, i.e., the action of Frobenius $\varphi$ on + the crystalline module $D_{p}(E)= \Q_{p} \otimes H^{1}_{dR}(E/\Q)$ in the basis of + the given model $(\omega, \eta=x\*\omega)$, where $\omega$ is the invariant + differential $dx/(2\*y+a_{1}\*x+a_{3})$. In other words, $\eta + s_{2}\omega$ + is an eigenvector for the unit eigenvalue of $\varphi$. + \bprog + ? e=ellinit([17,42]); + ? ellpadics2(e,13,4) + %2 = 10 + 2*13 + 6*13^3 + O(13^4) + @eprog + This slope is the unique $c \in 3^{-1}\Z_{p}$ such that the odd solution + $\sigma(t) = t + O(t^{2})$ of + $$ - d(\dfrac{1}{\sigma} \dfrac{d \sigma}{\omega}) + = (x(t) + c) \omega$$ + is in $t\Z_{p}[[t]]$. + + It is equal to $b_{2}/12 - E_{2}/12$ where $E_{2}$ is the value of the Katz + $p$-adic Eisenstein series of weight 2 on $(E,\omega)$. This is + used to construct a canonical $p$-adic height when $E$ has good ordinary + reduction at $p$ as follows + \bprog + s2 = ellpadics2(E,p,n); + h(E,p,n, P, s2) = ellpadicheight(E, [p,[1,-s2]],n, P); + @eprog\noindent Since $s_{2}$ does not depend on the point $P$, we compute it + only once. + +Function: ellperiods +Class: basic +Section: elliptic_curves +C-Name: ellperiods +Prototype: GD0,L,p +Help: ellperiods(w,{flag=0}): w describes a complex period lattice ([w1,w2] + or an ellinit structure). Returns normalized periods [W1,W2] generating the + same lattice such that tau := W1/W2 satisfies Im(tau) > 0 and lies in the + standard fundamental domain for SL2. If flag is 1, the return value is + [[W1,W2], [e1,e2]], where e1, e2 are the quasi-periods attached to + [W1,W2], satisfying e2 W1 - e1 W2 = 2 Pi I. +Doc: Let $w$ describe a complex period lattice ($w = [w_{1},w_{2}]$ + or an \kbd{ellinit} structure). Returns normalized periods $[W_{1},W_{2}]$ + generating the same lattice such that $\tau := W_{1}/W_{2}$ has positive + imaginary part and lies in the standard fundamental domain for + $\text{SL}_{2}(\Z)$. + + If $\fl = 1$, the function returns $[[W_{1},W_{2}], [\eta_{1},\eta_{2}]]$, + where $\eta_{1}$ and $\eta_{2}$ are the quasi-periods attached to + $[W_{1},W_{2}]$, satisfying $\eta_{2} W_{1} - \eta_{1} W_{2} = 2 i \pi$. + + The output of this function is meant to be used as the first argument + given to ellwp, ellzeta, ellsigma or elleisnum. Quasi-periods are + needed by ellzeta and ellsigma only. + + \bprog + ? L = ellperiods([1,I],1); + ? [w1,w2] = L[1]; [e1,e2] = L[2]; + ? e2*w1 - e1*w2 + %3 = 6.2831853071795864769252867665590057684*I + ? ellzeta(L, 1/2 + 2*I) + %4 = 1.5707963... - 6.283185307...*I + ? ellzeta([1,I], 1/2 + 2*I) \\ same but less efficient + %4 = 1.5707963... - 6.283185307...*I + @eprog + +Function: ellpointtoz +Class: basic +Section: elliptic_curves +C-Name: zell +Prototype: GGp +Help: ellpointtoz(E,P): lattice point z corresponding to the point P on the + elliptic curve E. +Doc: + if $E/\C \simeq \C/\Lambda$ is a complex elliptic curve ($\Lambda = + \kbd{E.omega}$), computes a complex number $z$, well-defined modulo the + lattice $\Lambda$, corresponding to the point $P$; i.e.~such that + $P = [\wp_{\Lambda}(z),\wp'_{\Lambda}(z)]$ satisfies the equation + $$y^{2} = 4x^{3} - g_{2} x - g_{3},$$ + where $g_{2}$, $g_{3}$ are the elliptic invariants. + + If $E$ is defined over $\R$ and $P\in E(\R)$, we have more precisely, $0 \leq + \Re(t) < w1$ and $0 \leq \Im(t) < \Im(w2)$, where $(w1,w2)$ are the real and + complex periods of $E$. + \bprog + ? E = ellinit([0,1]); P = [2,3]; + ? z = ellpointtoz(E, P) + %2 = 3.5054552633136356529375476976257353387 + ? ellwp(E, z) + %3 = 2.0000000000000000000000000000000000000 + ? ellztopoint(E, z) - P + %4 = [2.548947057811923643 E-57, 7.646841173435770930 E-57] + ? ellpointtoz(E, [0]) \\ the point at infinity + %5 = 0 + @eprog + + If $E$ is defined over a general number field, the function returns the + values corresponding to the various complex embeddings of the curve + and of the point, in the same order as \kbd{E.nf.roots}: + \bprog + ? E=ellinit([-22032-15552*x,0], nfinit(x^2-2)); + ? P=[-72*x-108,0]; + ? ellisoncurve(E,P) + %3 = 1 + ? ellpointtoz(E,P) + %4 = [-0.52751724240790530394437835702346995884*I, + -0.090507650025885335533571758708283389896*I] + ? E.nf.roots + %5 = [-1.4142135623730950488016887242096980786, \\ x-> -sqrt(2) + 1.4142135623730950488016887242096980786] \\ x-> sqrt(2) + @eprog + + If $E/\Q_{p}$ has multiplicative reduction, then $E/\bar{\Q_{p}}$ is + analytically + isomorphic to $\bar{\Q}_{p}^{*}/q^{\Z}$ (Tate curve) for some $p$-adic integer + $q$. The behavior is then as follows: + + \item If the reduction is split ($E.\kbd{tate[2]}$ is a \typ{PADIC}), we have + an isomorphism $\phi: E(\Q_{p}) \simeq \Q_{p}^{*}/q^{\Z}$ and the function + returns $\phi(P)\in \Q_{p}$. + + \item If the reduction is \emph{not} split ($E.\kbd{tate[2]}$ is a + \typ{POLMOD}), we only have an isomorphism $\phi: E(K) \simeq K^{*}/q^{\Z}$ + over the unramified quadratic extension $K/\Q_{p}$. In this case, the output + $\phi(P)\in K$ is a \typ{POLMOD}; the function is not fully implemented in + this case and may fail with a ``$u$ not in $\Q_{p}$'' exception: + \bprog + ? E = ellinit([0,-1,1,0,0], O(11^5)); P = [0,0]; + ? [u2,u,q] = E.tate; type(u) \\ split multiplicative reduction + %2 = "t_PADIC" + ? ellmul(E, P, 5) \\ P has order 5 + %3 = [0] + ? z = ellpointtoz(E, [0,0]) + %4 = 3 + 11^2 + 2*11^3 + 3*11^4 + 6*11^5 + 10*11^6 + 8*11^7 + O(11^8) + ? z^5 + %5 = 1 + O(11^9) + ? E = ellinit(ellfromj(1/4), O(2^6)); x=1/2; y=ellordinate(E,x)[1]; + ? z = ellpointtoz(E,[x,y]); \\ t_POLMOD of t_POL with t_PADIC coeffs + ? liftint(z) \\ lift all p-adics + %8 = Mod(8*u + 7, u^2 + 437) + ? x=33/4; y=ellordinate(E,x)[1]; z = ellpointtoz(E,[x,y]) + *** at top-level: ...;y=ellordinate(E,x)[1];z=ellpointtoz(E,[x,y]) + *** ^-------------------- + *** ellpointtoz: sorry, ellpointtoz when u not in Qp is not yet implemented. + @eprog + +Function: ellpow +Class: basic +Section: elliptic_curves +C-Name: ellmul +Prototype: GGG +Obsolete: 2012-06-06 +Help: ellpow(E,z,n): deprecated alias for ellmul. +Doc: deprecated alias for \kbd{ellmul}. + +Function: ellrank +Class: basic +Section: elliptic_curves +C-Name: ellrank +Prototype: GD0,L,DGp +Help: ellrank(E,{effort=0},{points}): if E is an elliptic curve over Q, + attempts to compute the Mordell-Weil group attached to the curve. + The output is [r1,r2,s,L], where r1 <= rank(E) <= r2, s gives information + on the Tate-Shafarevich group (see documentation), and and L is a list of + independent, non-torsion rational points on the curve. E can also be given as + the output of ellrankinit(E). +Doc: if $E$ is an elliptic curve over $\Q$, attempts to compute the + Mordell-Weil group attached to the curve. The output is $[r_{1},r_{2},s,L]$, + where + $r_{1} \le\text{rank}(E) \le r_{2}$, $s$ gives informations on the + Tate-Shafarevic group (see below), and $L$ is a list of independent, + non-torsion rational points on the curve. $E$ can also be given as the output + of \kbd{ellrankinit(E)}. + + If \kbd{points} is provided, it must be a vector of rational points on the + curve, which are not computed again. + + The parameter \kbd{effort} is a measure of the time employed to find rational + points before giving up. If \kbd{effort} is not $0$, the search is + randomized, so rerunning the function might yield different or even + a different number of rational points. Values up to $10$ or so are reasonable + but the parameter can be increased futher, with running times increasing + roughly like the \emph{cube} of the \kbd{effort} value. + + \bprog + ? E = ellinit([-127^2,0]); + ? ellrank(E) + %2 = [1, 1, 0, []] \\ rank is 1 but no point has been found. + ? ellrank(E,4) \\ with more effort we find a point. + %3 = [1, 1, 0, [[38902300445163190028032/305111826865145547009, + 680061120400889506109527474197680/5329525731816164537079693913473]]] + @eprog + + In addition to the previous calls, the first argument $E$ can be a pair + $[e,f]$, where $e$ is an elliptic curve given by \kbd{ellrankinit} and + $f$ is a quadratic twist of $e$. We then look for points on $f$. + Note that the \kbd{ellrankinit} initialization is independent of $f$, so + this can speed up computations significantly! + + \misctitle{Technical explanation} + The algorithm, which computes the $2$-descent and the $2$-part of the Cassels + pairings has an intrinsic limitation: $r_{1} = r_{2}$ never holds when + the Tate-Shafarevic group $G$ has $4$-torsion. Thus, in this case we cannot + determine the rank precisely. The algorithm computes unconditionally three + quantities: + + \item the rank $C$ of the $2$-Selmer group. + + \item the rank $T$ of the $2$-torsion subgroup. + + \item the (even) rank $s$ of $G[2]/2G[4]$; then $r_{2}$ is defined + by $r_{2} = C - T - s$. + + The following quantities are also relevant: + + \item the rank $R$ of the free part of $E(\Q)$; it always holds that + $r_{1} \le R \le r_{2}$. + + \item the rank $S$ of $G[2]$ (conjecturally even); it always holds that + $s \le S$ and that $C = T + R + S$. Then $r_{2} = C - T - s \ge R$. + + When the conductor of $E$ is small, the BSD conjecture can be used + to (conditionally) find the true rank: + \bprog + ? E=ellinit([-113^2,0]); + ? ellrootno(E) \\ rank is even (parity conjecture) + %2 = 1 + ? ellrank(E) + %3 = [0, 2, 0, []] \\ rank is either 0 or 2, $2$-rank of $G$ is + ? ellrank(E, 3) \\ try harder + %4 = [0, 2, 0, []] \\ no luck + ? [r,L] = ellanalyticrank(E) \\ assume BSD + %5 = [0, 3.9465...] + ? L / ellbsd(E) \\ analytic rank is 0, compute Sha + %6 = 16.0000000000000000000000000000000000000 + @eprog + We find that the rank is $0$ and the cardinal of the Tate-Shafarevich group + is $16$ (assuming BSD!). Moreover, since $s=0$, it is isomorphic to + $(\Z/4\Z)^{2}$. + + When the rank is $1$ and the conductor is small, \kbd{ellheegner} can be used + to find a non-torsion point: + \bprog + ? E = ellinit([-157^2,0]); + ? ellrank(E) + %2 = [1, 1, 0, []] \\ rank is 1, no point found + ? ellrank(E, 5) \\ Try harder + time = 1,094 ms. + %3 = [1, 1, 0, []] \\ No luck + ? ellheegner(E) \\ use analytic method + time = 492 ms. + %4 = [69648970982596494254458225/166136231668185267540804, ...] + @eprog\noindent In this last example, an \kbd{effort} about 10 would also + (with probability about 80\%) find a random point, not necessarily the + Heegner point, in about 5 seconds. + +Function: ellrankinit +Class: basic +Section: elliptic_curves +C-Name: ellrankinit +Prototype: Gp +Help: ellrankinit(E): if E is an elliptic curve over Q, + initialize data for further calls to ellrank. +Doc: if $E$ is an elliptic curve over $\Q$, initialize data to speed up further + calls to \kbd{ellrank}. + \bprog + ? E = ellinit([0,2429469980725060,0,275130703388172136833647756388,0]); + ? rk = ellrankinit(E); + ? [r, R, s, P] = ellrank(rk) + %3 = [12, 14, 0, [...]] + ? [r, R, s, P] = ellrank(rk, 1, P) \\ more effort, using known points + %4 = [14, 14, 0, [...]] \\ this time all points are found + @eprog + +Function: ellratpoints +Class: basic +Section: elliptic_curves +C-Name: ellratpoints +Prototype: GGD0,L, +Help: ellratpoints(E,h,{flag=0}): E being an rational model of an + elliptic curve, return a vector containing the affine rational points on the curve + of naive height less than h. + If fl=1, stop as soon as a point is found. +Doc: $E$ being an integral model of elliptic curve , return a vector + containing the affine rational points on the curve of naive height less than + $h$. If $\fl=1$, stop as soon as a point is found; return either an empty + vector or a vector containing a single point. + See \kbd{hyperellratpoints} for how $h$ can be specified. + \bprog + ? E=ellinit([-25,1]); + ? ellratpoints(E,10) + %2 = [[-5,1],[-5,-1],[-3,7],[-3,-7],[-1,5],[-1,-5], + [0,1],[0,-1],[5,1],[5,-1],[7,13],[7,-13]] + ? ellratpoints(E,10,1) + %3 = [[-5,1]] + @eprog + +Function: ellrootno +Class: basic +Section: elliptic_curves +C-Name: ellrootno +Prototype: lGDG +Help: ellrootno(E,{p}): root number for the L-function of the elliptic + curve E/Q at a prime p (including 0, for the infinite place); global root + number if p is omitted. If p is omitted, the curve can also be defined over + a number field. +Doc: $E$ being an \kbd{ell} structure over $\Q$ as output by \kbd{ellinit}, + this function computes the local root number of its $L$-series at the place + $p$ (at the infinite place if $p = 0$). If $p$ is omitted, return the global + root number and in this case the curve can also be defined over a number field. + + Note that the global root number is the sign of the functional + equation and conjecturally is the parity of the rank of the + \idx{Mordell-Weil group}. The equation for $E$ needs not be minimal at $p$, + but if the model is already minimal the function will run faster. + +Function: ellsaturation +Class: basic +Section: elliptic_curves +C-Name: ellsaturation +Prototype: GGLp +Help: ellsaturation(E,V,B): let E be an elliptic curve over Q + and V be a vector of independent rational points on E of infinite order that + generate a subgroup G of E(Q) of finite index. + Return a new set W of the same length that generate a subgroup H of + E(Q) containing G and such that [E(Q):H] is not divisible by any prime + number less than B. +Doc: Let $E$ be an elliptic curve over $\Q$ and + and $V$ be a set of independent non-torsion rational points on $E$ of infinite + order that generate a subgroup $G$ of $E(\Q)$ of finite index. + Return a new set $W$ of the same length that generate a subgroup $H$ of + $E(\Q)$ containing $G$ and such that $[E(\Q):H]$ is not divisible by any + prime number less than $B$. The running time is roughly quadratic in $B$. + + \bprog + ? E = ellinit([0,0, 1, -7, 6]); + ? [r,R,s,V] = ellrank(E) + %2 = [3, 3, 0, [[-1,3], [-3,0], [11,35]]] + ? matdet(ellheightmatrix(E, V)) + %3 = 3.7542920288254557283540759015628405708 + ? W = ellsaturation(E, V, 2) \\ index is now odd + time = 1 ms. + %4 = [[-1, 3], [-3, 0], [11, 35]] + ? W = ellsaturation(E, W, 10) \\ index not divisible by p <= 10 + %5 = [[1, -1], [2, -1], [0, -3]] + time = 2 ms. + ? W = ellsaturation(E, V, 100) \\ looks OK now + time = 171 ms. + %6 = [[1, -1], [2, -1], [0, -3]] + ? matdet(ellheightmatrix(E,V)) + %7 = 0.41714355875838396981711954461809339675 + ? lfun(E,1,3)/3! / ellbsd(E) \\ conductor is small, check assuming BSD + %8 = 0.41714355875838396981711954461809339675 + @eprog + +Function: ellsea +Class: basic +Section: elliptic_curves +C-Name: ellsea +Prototype: GD0,L, +Help: ellsea(E,{tors=0}): computes the order of the group E(Fq) + for the elliptic curve E, defined over a finite field, + using SEA algorithm, with early abort for curves (or their quadratic + twist) with nonprime order. +Doc: Let $E$ be an \var{ell} structure as output by \kbd{ellinit}, defined over + a finite field $\F_{q}$. This low-level function computes the order of the + group $E(\F_{q})$ using the SEA algorithm; compared to the high-level + function \kbd{ellcard}, which includes SEA among its choice of algorithms, + the \kbd{tors} argument allows to speed up a search for curves having almost + prime order and whose quadratic twist may also have almost prime order. + When \kbd{tors} is set to a nonzero value, the function returns $0$ as soon + as it detects that the order has a small prime factor not dividing \kbd{tors}; + SEA considers modular polynomials of increasing prime degree $\ell$ and we + return $0$ as soon as we hit an $\ell$ (coprime to \kbd{tors}) dividing + $\#E(\F_{q})$: + \bprog + ? ellsea(ellinit([1,1], 2^56+3477), 1) + %1 = 72057594135613381 + ? forprime(p=2^128,oo, q = ellcard(ellinit([1,1],p)); if(isprime(q),break)) + time = 6,571 ms. + ? forprime(p=2^128,oo, q = ellsea(ellinit([1,1],p),1);if(isprime(q),break)) + time = 522 ms. + @eprog\noindent + In particular, set \kbd{tors} to $1$ if you want a curve with prime order, + to $2$ if you want to allow a cofactor which is a power of two (e.g. for + Edwards's curves), etc. The early exit on bad curves yields a massive + speedup compared to running the cardinal algorithm to completion. + + When \kbd{tors} is negative, similar checks are performed for the quadratic + twist of the curve. + + The following function returns a curve of prime order over $\F_{p}$. + \bprog + cryptocurve(p) = + { + while(1, + my(E, N, j = Mod(random(p), p)); + E = ellinit(ellfromj(j)); + N = ellsea(E, 1); if (!N, continue); + if (isprime(N), return(E)); + \\ try the quadratic twist for free + if (isprime(2*p+2 - N), return(elltwist(E))); + ); + } + ? p = randomprime([2^255, 2^256]); + ? E = cryptocurve(p); \\ insist on prime order + %2 = 47,447ms + @eprog\noindent The same example without early abort (using \kbd{ellcard(E)} + instead of \kbd{ellsea(E, 1)}) runs for about 5 minutes before finding a + suitable curve. + + The availability of the \kbd{seadata} package will speed up the computation, + and is strongly recommended. The generic function \kbd{ellcard} should be + preferred when you only want to compute the cardinal of a given curve without + caring about it having almost prime order: + + \item If the characteristic is too small ($p \leq 7$) or the field + cardinality is tiny ($q \leq 523$) the generic algorithm + \kbd{ellcard} is used instead and the \kbd{tors} argument is ignored. + (The reason for this is that SEA is not implemented for $p \leq 7$ and + that if $q \leq 523$ it is likely to run into an infinite loop.) + + \item If the field cardinality is smaller than about $2^{50}$, the + generic algorithm will be faster. + + \item Contrary to \kbd{ellcard}, \kbd{ellsea} does not store the computed + cardinality in $E$. + +Function: ellsearch +Class: basic +Section: elliptic_curves +C-Name: ellsearch +Prototype: G +Help: ellsearch(N): returns all curves in the elldata database matching + constraint N: given name (N = "11a1" or [11,0,1]), + given isogeny class (N = "11a" or [11,0]), or + given conductor (N = 11, "11", or [11]). +Doc: This function finds all curves in the \tet{elldata} database satisfying + the constraint defined by the argument $N$: + + \item if $N$ is a character string, it selects a given curve, e.g. + \kbd{"11a1"}, or curves in the given isogeny class, e.g. \kbd{"11a"}, or + curves with given conductor, e.g. \kbd{"11"}; + + \item if $N$ is a vector of integers, it encodes the same constraints + as the character string above, according to the \tet{ellconvertname} + correspondance, e.g. \kbd{[11,0,1]} for \kbd{"11a1"}, \kbd{[11,0]} for + \kbd{"11a"} and \kbd{[11]} for \kbd{"11"}; + + \item if $N$ is an integer, curves with conductor $N$ are selected. + + If $N$ codes a full curve name, for instance \kbd{"11a1"} or \kbd{[11,0,1]}, + the output format is $[N, [a_{1},a_{2},a_{3},a_{4},a_{6}], G]$ where + $[a_{1},a_{2},a_{3},a_{4},a_{6}]$ are the coefficients of the Weierstrass + equation of the curve and $G$ is a $\Z$-basis of the free part of the + \idx{Mordell-Weil group} attached to the curve. + \bprog + ? ellsearch("11a3") + %1 = ["11a3", [0, -1, 1, 0, 0], []] + ? ellsearch([11,0,3]) + %2 = ["11a3", [0, -1, 1, 0, 0], []] + @eprog\noindent + + If $N$ is not a full curve name, then the output is a vector of all matching + curves in the above format: + \bprog + ? ellsearch("11a") + %1 = [["11a1", [0, -1, 1, -10, -20], []], + ["11a2", [0, -1, 1, -7820, -263580], []], + ["11a3", [0, -1, 1, 0, 0], []]] + ? ellsearch("11b") + %2 = [] + @eprog +Variant: Also available is \fun{GEN}{ellsearchcurve}{GEN N} that only + accepts complete curve names (as \typ{STR}). + +Function: ellsigma +Class: basic +Section: elliptic_curves +C-Name: ellsigma +Prototype: GDGD0,L,p +Help: ellsigma(L,{z='x},{flag=0}): computes the value at z of the Weierstrass + sigma function attached to the lattice L, as given by ellperiods(,1). + If flag = 1, returns an arbitrary determination of the logarithm of sigma. +Doc: Computes the value at $z$ of the Weierstrass $\sigma$ function attached to + the lattice $L$ as given by \tet{ellperiods}$(,1)$: including quasi-periods + is useful, otherwise there are recomputed from scratch for each new $z$. + $$ \sigma(z, L) = z \prod_{\omega\in L^{*}} \left(1 - \dfrac{z}{\omega}\right) + e^{\dfrac{z}{\omega} + \dfrac{z^{2}}{2\omega^{2}}}.$$ + It is also possible to directly input $L = [\omega_{1},\omega_{2}]$, + or an elliptic curve $E$ as given by \kbd{ellinit} ($L = \kbd{E.omega}$). + \bprog + ? w = ellperiods([1,I], 1); + ? ellsigma(w, 1/2) + %2 = 0.47494937998792065033250463632798296855 + ? E = ellinit([1,0]); + ? ellsigma(E) \\ at 'x, implicitly at default seriesprecision + %4 = x + 1/60*x^5 - 1/10080*x^9 - 23/259459200*x^13 + O(x^17) + @eprog + + If $\fl=1$, computes an arbitrary determination of $\log(\sigma(z))$. + +Function: ellsub +Class: basic +Section: elliptic_curves +C-Name: ellsub +Prototype: GGG +Help: ellsub(E,z1,z2): difference of the points z1 and z2 on elliptic curve E. +Doc: + difference of the points $z1$ and $z2$ on the + elliptic curve corresponding to $E$. + +Function: ellsupersingularj +Class: basic +Section: elliptic_curves +C-Name: ellsupersingularj +Prototype: G +Help: ellsupersingularj(p): return a random supersingular j-invariant defined + over F_p^2 if p is prime number, over the (finite) field of definition of p + otherwise +Doc: + return a random supersingular $j$-invariant defined over $\F_{p}^{2}$ as a + \typ{FFELT} in the variable \kbd{w}, if $p$ is a prime number, or over the + field of definition of $p$ if $p$ is a \typ{FFELT}. The field must be of even + degree. The random distribution is close to uniform except when $0$ or + $1728$ are supersingular $j$-invariants, in which case they are less + likely to be returned. This bias becomes negligible as $p$ grows. + \bprog + ? j = ellsupersingularj(1009) + %1 = 12*w+295 + ? ellissupersingular(j) + %2 = 1 + ? a = ffgen([1009,2],'a); + ? j = ellsupersingularj(a) + %4 = 867*a+721 + ? ellissupersingular(j) + %5 = 1 + ? E = ellinit([j]); + ? F = elltwist(E); + ? ellissupersingular(F) + %8 = 1 + ? ellap(E) + %9 = 2018 + ? ellap(F) + %10 = -2018 + @eprog + +Function: elltamagawa +Class: basic +Section: elliptic_curves +C-Name: elltamagawa +Prototype: G +Help: elltamagawa(E): E being an elliptic curve over a number field, + returns the global Tamagawa number of the curve. +Doc: + The object $E$ being an elliptic curve over a number field, returns the global + Tamagawa number of the curve (including the factor at infinite places). + \bprog + ? e = ellinit([1, -1, 1, -3002, 63929]); \\ curve "90c6" from elldata + ? elltamagawa(e) + %2 = 288 + ? [elllocalred(e,p)[4] | p<-[2,3,5]] + %3 = [6, 4, 6] + ? vecprod(%) \\ since e.disc > 0 the factor at infinity is 2 + %4 = 144 + ? ellglobalred(e)[4] \\ product without the factor at infinity + %5 = 144 + @eprog + +Function: elltaniyama +Class: basic +Section: elliptic_curves +C-Name: elltaniyama +Prototype: GDP +Help: elltaniyama(E,{n=seriesprecision}): modular parametrization of + elliptic curve E/Q. +Doc: + computes the modular parametrization of the elliptic curve $E/\Q$, + where $E$ is an \kbd{ell} structure as output by \kbd{ellinit}. This returns + a two-component vector $[u,v]$ of power series, given to $n$ significant + terms (\tet{seriesprecision} by default), characterized by the following two + properties. First the point $(u,v)$ satisfies the equation of the elliptic + curve. Second, let $N$ be the conductor of $E$ and $\Phi: X_{0}(N)\to E$ + be a modular parametrization; the pullback by $\Phi$ of the + N\'eron differential $du/(2v+a_{1}u+a_{3})$ is equal to $2i\pi + f(z)dz$, a holomorphic differential form. The variable used in the power + series for $u$ and $v$ is $x$, which is implicitly understood to be equal to + $\exp(2i\pi z)$. + + The algorithm assumes that $E$ is a \emph{strong} \idx{Weil curve} + and that the Manin constant is equal to 1: in fact, $f(x) = \sum_{n > 0} + \kbd{ellak}(E, n) x^{n}$. + +Function: elltatepairing +Class: basic +Section: elliptic_curves +C-Name: elltatepairing +Prototype: GGGG +Help: elltatepairing(E,P,Q,m): computes the Tate pairing of the two points + P and Q on the elliptic curve E. The point P must be of m-torsion. +Doc: Let $E$ be an elliptic curve defined over a finite field $k$ + and $m \geq 1$ be an integer. This function computes the (nonreduced) Tate + pairing of the points $P$ and $Q$ on $E$, where $P$ is an $m$-torsion point. + More precisely, let $f_{m,P}$ denote a Miller function with divisor $m[P] - + m[O_{E}]$; the algorithm returns $f_{m,P}(Q) \in k^{*}/(k^{*})^{m}$. + +Function: elltors +Class: basic +Section: elliptic_curves +C-Name: elltors +Prototype: G +Help: elltors(E): torsion subgroup of elliptic curve E: order, structure, + generators. +Doc: + if $E$ is an elliptic curve defined over a number field or a finite field, + outputs the torsion subgroup of $E$ as a 3-component vector \kbd{[t,v1,v2]}, + where \kbd{t} is the order of the torsion group, \kbd{v1} gives the structure + of the torsion group as a product of cyclic groups (sorted by decreasing + order), and \kbd{v2} gives generators for these cyclic groups. $E$ must be an + \kbd{ell} structure as output by \kbd{ellinit}. + \bprog + ? E = ellinit([-1,0]); + ? elltors(E) + %1 = [4, [2, 2], [[0, 0], [1, 0]]] + @eprog\noindent + Here, the torsion subgroup is isomorphic to $\Z/2\Z \times \Z/2\Z$, with + generators $[0,0]$ and $[1,0]$. + +Function: elltrace +Class: basic +Section: elliptic_curves +C-Name: elltrace +Prototype: GG +Help: elltrace(E,P): sum of the Galois conjugates of the point P on elliptic + curve E. +Doc: let $E$ be an elliptic curve over a base field and a point $P$ defined + over an extension field using \typ{POLMOD} constructs. Returns the sum of + the Galois conjugates of $P$. + The field over which $P$ is defined must be specified, even in the (silly) + case of a trivial extension: + \bprog + ? E = ellinit([1,15]); \\ y^2 = x^3 + x + 15, over Q + ? P = Mod([a/8-1, 1/32*a^2-11/32*a-19/4], a^3-135*a-408); + ? ellisoncurve(E,P) \\ P defined over a cubic extension + %3 = 1 + ? elltrace(E,P) + %4 = [2,-5] + @eprog + + \bprog + ? E = ellinit([-13^2, 0]); + ? P = Mod([13,0], a^2-2); \\ defined over Q, seen over a quadratic extension + ? elltrace(E,P) == ellmul(E,P,2) + %3 = 1 + ? elltrace(E,[13,0]) \\ number field of definition of the point unspecified! + *** at top-level: elltrace(E,[13,0]) + *** ^------------------ + *** elltrace: incorrect type in elltrace (t_INT). + ? elltrace(E,Mod([13,0],a)) \\ trivial extension + %5 = [Mod(13, a), Mod(0, a)] + ? P = Mod([-10*x^3+10*x-13, -16*x^3+16*x-34], x^4-x^3+2*x-1); + ? ellisoncurve(E,P) + %7 = 1 + ? Q = elltrace(E,P) + %8 = [11432100241 / 375584400, 1105240264347961 / 7278825672000] + ? ellisoncurve(E,Q) + %9 = 1 + @eprog + + \bprog + ? E = ellinit([2,3], 19); \\ over F_19 + ? T = a^5+a^4+15*a^3+16*a^2+3*a+1; \\ irreducible + ? P = Mod([11*a^3+11*a^2+a+12,15*a^4+9*a^3+18*a^2+18*a+6], T); + ? ellisoncurve(E, P) + %4 = 1 + ? Q = elltrace(E, P) + %5 = [Mod(1,19), Mod(14,19)] + ? ellisoncurve(E, Q) + %6 = 1 + @eprog + +Function: elltwist +Class: basic +Section: elliptic_curves +C-Name: elltwist +Prototype: GDG +Help: elltwist(E,{P}): returns an ell structure for the twist of the elliptic + curve E by the quadratic extension defined by P (when P is a polynomial of + degree 2) or quadpoly(P) (when P is an integer). If E is defined over a + finite field, then P can be omitted. +Doc: returns an \kbd{ell} structure (as given by \kbd{ellinit}) for the twist + of the elliptic curve $E$ by the quadratic extension of the coefficient + ring defined by $P$ (when $P$ is a polynomial) or \kbd{quadpoly(P)} when $P$ + is an integer. If $E$ is defined over a finite field, then $P$ can be + omitted, in which case a random model of the unique nontrivial twist is + returned. If $E$ is defined over a number field, the model should be + replaced by a minimal model (if one exists). + + The elliptic curve $E$ can be given in some of the formats allowed by + \kbd{ellinit}: an \kbd{ell} structure, a $5$-component vector + $[a_{1},a_{2},a_{3},a_{4},a_{6}]$ or a $2$-component vector $[a_{4},a_{6}]$. + + Twist by discriminant $-3$: + \bprog + ? elltwist([0,a2,0,a4,a6], -3)[1..5] + %1 = [0, -3*a2, 0, 9*a4, -27*a6] + ? elltwist([a4,a6], -3)[1..5] + %2 = [0, 0, 0, 9*a4, -27*a6] + @eprog + Twist by the Artin-Schreier extension given by $x^{2}+x+T$ in + characteristic $2$: + \bprog + ? lift(elltwist([a1,a2,a3,a4,a6]*Mod(1,2), x^2+x+T)[1..5]) + %1 = [a1, a2+a1^2*T, a3, a4, a6+a3^2*T] + @eprog + Twist of an elliptic curve defined over a finite field: + \bprog + ? E = elltwist([1,7]*Mod(1,19)); lift([E.a4, E.a6]) + %1 = [11, 12] + @eprog + +Function: ellweilcurve +Class: basic +Section: elliptic_curves +C-Name: ellweilcurve +Prototype: GD& +Help: ellweilcurve(E,{&ms}): let E be an elliptic curve over Q given by + ellinit or a rational isogeny class given by ellisomat. Return a list + of isomorphism classes of elliptic curves isogenous to E as given by ellisomat + and the list of the Smith invariants of the lattice associated to E in + H^1(E,Q) in the lattice associated to the modular form. If ms is present, + it contains the output of msfromell(Emin,0) where Emin is the list of minimal + models attached to the curves in the isogeny class. +Doc: If $E'$ is an elliptic curve over $\Q$, let $L_{E'}$ be the + sub-$\Z$-module of $\Hom_{\Gamma_{0}(N)}(\Delta_{0},\Q)$ attached to $E'$ + (It is given by $x[3]$ if $[M,x] = \kbd{msfromell}(E')$.) + + On the other hand, if $N$ is the conductor of $E$ and $f$ is the modular form + for $\Gamma_{0}(N)$ attached to $E$, let $L_{f}$ be the lattice of the + $f$-component of $\Hom_{\Gamma_{0}(N)}(\Delta_{0},\Q)$ given by the elements + $\phi$ such that $\phi(\{0,\gamma^{-1} 0\}) \in \Z$ for all + $\gamma \in \Gamma_{0}(N)$ (see \tet{mslattice}). + + Let $E'$ run through the isomorphism classes of elliptic curves + isogenous to $E$ as given by \kbd{ellisomat} (and in the same order). + This function returns a pair \kbd{[vE,vS]} where \kbd{vE} contains minimal + models for the $E'$ and \kbd{vS} contains the list of Smith invariants for + the lattices $L_{E'}$ in $L_{f}$. The function also accepts the output of + \kbd{ellisomat}, i.e. the isogeny class. If the optional argument \kbd{ms} + is present, it contains the output of \kbd{msfromell(vE, 0)}, i.e. the new + modular symbol space $M$ of level $N$ and a vector of triples + $[x^{+},x^{-}, L]$ attached to each curve $E'$. + + In particular, the strong Weil curve amongst the curves isogenous to $E$ + is the one whose Smith invariants are $[c,c]$, where $c$ is the Manin + constant, conjecturally equal to $1$. + \bprog + ? E = ellinit("11a3"); + ? [vE, vS] = ellweilcurve(E); + ? [n] = [ i | i<-[1..#vS], vS[i]==[1,1] ] \\ lattice with invariant [1,1] + %3 = [2] + ? ellidentify(vE[n]) \\ ... corresponds to strong Weil curve + %4 = [["11a1", [0, -1, 1, -10, -20], []], [1, 0, 0, 0]] + + ? [vE, vS] = ellweilcurve(E, &ms); \\ vE,vS are as above + ? [M, vx] = ms; msdim(M) \\ ... but ms contains more information + %6 = 3 + ? #vx + %7 = 3 + ? vx[1] + %8 = [[1/25, -1/10, -1/10]~, [0, 1/2, -1/2]~, [1/25,0; -3/5,1; 2/5,-1]] + ? forell(E, 11,11, print(msfromell(ellinit(E[1]), 1)[2])) + [1/5, -1/2, -1/2]~ + [1, -5/2, -5/2]~ + [1/25, -1/10, -1/10]~ + @eprog\noindent The last example prints the modular symbols $x^{+}$ + in $M^{+}$ attached to the curves \kbd{11a1}, \kbd{11a2} and \kbd{11a3}. + +Function: ellweilpairing +Class: basic +Section: elliptic_curves +C-Name: ellweilpairing +Prototype: GGGG +Help: ellweilpairing(E,P,Q,m): computes the Weil pairing of the two points + of m-torsion P and Q on the elliptic curve E. +Doc: Let $E$ be an elliptic curve defined over a finite field and $m \geq 1$ + be an integer. This function computes the Weil pairing of the two $m$-torsion + points $P$ and $Q$ on $E$, which is an alternating bilinear map. + More precisely, let $f_{m,R}$ denote a Miller function with + divisor $m[R] - m[O_{E}]$; the algorithm returns the $m$-th root of unity + $$\varepsilon(P,Q)^{m} \cdot f_{m,P}(Q) / f_{m,Q}(P),$$ + where $f(R)$ is the extended evaluation of $f$ at the divisor $[R] - [O_{E}]$ + and $\varepsilon(P,Q)\in \{\pm1\}$ is given by Weil reciprocity: + $\varepsilon(P,Q) = 1$ if and only if $P, Q, O_{E}$ are not pairwise distinct. + +Function: ellwp +Class: basic +Section: elliptic_curves +C-Name: ellwp0 +Prototype: GDGD0,L,p +Help: ellwp(w,{z='x},{flag=0}): computes the value at z of the Weierstrass P + function attached to the lattice w, as given by ellperiods. Optional flag + means 0 (default), compute only P(z), 1 compute [P(z),P'(z)]. +Doc: Computes the value at $z$ of the Weierstrass $\wp$ function attached to + the lattice $w$ as given by \tet{ellperiods}. It is also possible to + directly input $w = [\omega_{1},\omega_{2}]$, or an elliptic curve $E$ as + given by \kbd{ellinit} ($w = \kbd{E.omega}$). + \bprog + ? w = ellperiods([1,I]); + ? ellwp(w, 1/2) + %2 = 6.8751858180203728274900957798105571978 + ? E = ellinit([1,1]); + ? ellwp(E, 1/2) + %4 = 3.9413112427016474646048282462709151389 + @eprog\noindent One can also compute the series expansion around $z = 0$: + \bprog + ? E = ellinit([1,0]); + ? ellwp(E) \\ 'x implicitly at default seriesprecision + %5 = x^-2 - 1/5*x^2 + 1/75*x^6 - 2/4875*x^10 + O(x^14) + ? ellwp(E, x + O(x^12)) \\ explicit precision + %6 = x^-2 - 1/5*x^2 + 1/75*x^6 + O(x^9) + @eprog + + Optional \fl\ means 0 (default): compute only $\wp(z)$, 1: compute + $[\wp(z),\wp'(z)]$. + + For instance, the Dickson elliptic functions \var{sm} and \var{sn} can be + implemented as follows + \bprog + smcm(z) = + { my(a, b, E = ellinit([0,-1/(4*27)])); \\ ell. invariants (g2,g3)=(0,1/27) + [a,b] = ellwp(E, z, 1); + [6*a / (1-3*b), (3*b+1)/(3*b-1)]; + } + ? [s,c] = smcm(0.5); + ? s + %2 = 0.4898258757782682170733218609 + ? c + %3 = 0.9591820206453842491187464098 + ? s^3+c^3 + %4 = 1.000000000000000000000000000 + ? smcm('x + O('x^11)) + %5 = [x - 1/6*x^4 + 2/63*x^7 - 13/2268*x^10 + O(x^11), + 1 - 1/3*x^3 + 1/18*x^6 - 23/2268*x^9 + O(x^10)] + @eprog +Variant: For $\fl = 0$, we also have + \fun{GEN}{ellwp}{GEN w, GEN z, long prec}, and + \fun{GEN}{ellwpseries}{GEN E, long v, long precdl} for the power series in + variable $v$. + +Function: ellxn +Class: basic +Section: elliptic_curves +C-Name: ellxn +Prototype: GLDn +Help: ellxn(E,n,{v='x}): return polynomials [A,B] in the variable v such that + x([n]P) = (A/B)(t) for any P = [t,u] on E outside of n-torsion. +Doc: For any affine point $P = (t,u)$ on the curve $E$, we have + $$[n]P = (\phi_{n}(P)\psi_{n}(P) : \omega_{n}(P) : \psi_{n}(P)^{3})$$ + for some $\phi_{n},\omega_{n},\psi_{n}$ in $\Z[a_{1},a_{2},a_{3},a_{4},a_{6}][t,u]$ + modulo the curve equation. This function returns a pair $[A,B]$ of polynomials + in $\Z[a_{1},a_{2},a_{3},a_{4},a_{6}][v]$ such that $[A(t),B(t)] + = [\phi_{n}(P),\psi_{n}(P)^{2}]$ in the function field of $E$, + whose quotient give the abscissa of $[n]P$. If $P$ is an $n$-torsion point, + then $B(t) = 0$. + \bprog + ? E = ellinit([17,42]); [t,u] = [114,1218]; + ? T = ellxn(E, 2, 'X) + %2 = [X^4 - 34*X^2 - 336*X + 289, 4*X^3 + 68*X + 168] + ? [a,b] = subst(T,'X,t); + %3 = [168416137, 5934096] + ? a / b == ellmul(E, [t,u], 2)[1] + %4 = 1 + @eprog + +Function: ellzeta +Class: basic +Section: elliptic_curves +C-Name: ellzeta +Prototype: GDGp +Help: ellzeta(w,{z='x}): computes the value at z of the Weierstrass Zeta + function attached to the lattice w, as given by ellperiods(,1). +Doc: Computes the value at $z$ of the Weierstrass $\zeta$ function attached to + the lattice $w$ as given by \tet{ellperiods}$(,1)$: including quasi-periods + is useful, otherwise there are recomputed from scratch for each new $z$. + $$ \zeta(z, L) = \dfrac{1}{z} + z^{2}\sum_{\omega\in L^{*}} + \dfrac{1}{\omega^{2}(z-\omega)}.$$ + It is also possible to directly input $w = [\omega_{1},\omega_{2}]$, + or an elliptic curve $E$ as given by \kbd{ellinit} ($w = \kbd{E.omega}$). + The quasi-periods of $\zeta$, such that + $$\zeta(z + a\omega_{1} + b\omega_{2}) = \zeta(z) + a\eta_{1} + b\eta_{2} $$ + for integers $a$ and $b$ are obtained as $\eta_{i} = 2\zeta(\omega_{i}/2)$. + Or using directly \tet{elleta}. + \bprog + ? w = ellperiods([1,I],1); + ? ellzeta(w, 1/2) + %2 = 1.5707963267948966192313216916397514421 + ? E = ellinit([1,0]); + ? ellzeta(E, E.omega[1]/2) + %4 = 0.84721308479397908660649912348219163647 + @eprog\noindent One can also compute the series expansion around $z = 0$ + (the quasi-periods are useless in this case): + \bprog + ? E = ellinit([0,1]); + ? ellzeta(E) \\ at 'x, implicitly at default seriesprecision + %4 = x^-1 + 1/35*x^5 - 1/7007*x^11 + O(x^15) + ? ellzeta(E, x + O(x^20)) \\ explicit precision + %5 = x^-1 + 1/35*x^5 - 1/7007*x^11 + 1/1440257*x^17 + O(x^18) + @eprog\noindent + +Function: ellztopoint +Class: basic +Section: elliptic_curves +C-Name: pointell +Prototype: GGp +Help: ellztopoint(E,z): inverse of ellpointtoz. Returns the coordinates of + point P on the curve E corresponding to a complex or p-adic z. +Doc: + $E$ being an \var{ell} as output by + \kbd{ellinit}, computes the coordinates $[x,y]$ on the curve $E$ + corresponding to the complex or $p$-adic parameter $z$. Hence this is the + inverse function of \kbd{ellpointtoz}. + + \item If $E$ is defined over a $p$-adic field and has multiplicative + reduction, then $z$ is understood as an element on the + Tate curve $\bar{Q}_{p}^{*} / q^{\Z}$. + \bprog + ? E = ellinit([0,-1,1,0,0], O(11^5)); + ? [u2,u,q] = E.tate; type(u) + %2 = "t_PADIC" \\ split multiplicative reduction + ? z = ellpointtoz(E, [0,0]) + %3 = 3 + 11^2 + 2*11^3 + 3*11^4 + 6*11^5 + 10*11^6 + 8*11^7 + O(11^8) + ? ellztopoint(E,z) + %4 = [O(11^9), O(11^9)] + + ? E = ellinit(ellfromj(1/4), O(2^6)); x=1/2; y=ellordinate(E,x)[1]; + ? z = ellpointtoz(E,[x,y]); \\ nonsplit: t_POLMOD with t_PADIC coefficients + ? P = ellztopoint(E, z); + ? P[1] \\ y coordinate is analogous, more complicated + %8 = Mod(O(2^4)*x + (2^-1 + O(2^5)), x^2 + (1 + 2^2 + 2^4 + 2^5 + O(2^7))) + @eprog + + \item If $E$ is defined over the complex numbers (for instance over $\Q$), + $z$ is understood as a complex number in $\C/\Lambda_{E}$. If the + short Weierstrass equation is $y^{2} = 4x^{3} - g_{2}x - g_{3}$, then $[x,y]$ + represents the Weierstrass $\wp$-function\sidx{Weierstrass $\wp$-function} + and its derivative. For a general Weierstrass equation we have + $$x = \wp(z) - b_{2}/12,\quad y = \wp'(z)/2 - (a_{1} x + a_{3})/2.$$ + If $z$ is in the lattice defining $E$ over $\C$, the result is the point at + infinity $[0]$. + \bprog + ? E = ellinit([0,1]); P = [2,3]; + ? z = ellpointtoz(E, P) + %2 = 3.5054552633136356529375476976257353387 + ? ellwp(E, z) + %3 = 2.0000000000000000000000000000000000000 + ? ellztopoint(E, z) - P + %4 = [2.548947057811923643 E-57, 7.646841173435770930 E-57] + ? ellztopoint(E, 0) + %5 = [0] \\ point at infinity + @eprog + +Function: erfc +Class: basic +Section: transcendental +C-Name: gerfc +Prototype: Gp +Help: erfc(x): complementary error function. +Doc: complementary error function, analytic continuation of + $(2/\sqrt\pi)\int_{x}^{\infty} e^{-t^{2}}\,dt + = \text{sign(x)}\kbd{incgam}(1/2,x^{2})/\sqrt\pi$ for real $x \neq 0$. + The latter expression extends the function definition from real $x$ to + complex $x$ with positive real part (or zero real part and positive + imaginary part). This is extended to the whole complex plane by + the functional equation $\kbd{erfc}(-x) = 2 - \kbd{erfc}(x)$. + \bprog + ? erfc(0) + %1 = 1.0000000000000000000000000000000000000 + ? erfc(1) + %2 = 0.15729920705028513065877936491739074071 + ? erfc(1+I) + %3 = -0.31615128169794764488027108024367036903 + - 0.19045346923783468628410886196916244244*I + @eprog + +Function: errname +Class: basic +Section: programming/specific +C-Name: errname +Prototype: G +Help: errname(E): returns the type of the error message E. +Description: + (gen):errtyp err_get_num($1) +Doc: returns the type of the error message \kbd{E} as a string. + \bprog + ? iferr(1 / 0, E, print(errname(E))) + e_INV + ? ?? e_INV + [...] + * "e_INV". Tried to invert a noninvertible object x in function s. + [...] + @eprog + +Function: error +Class: basic +Section: programming/specific +C-Name: error0 +Prototype: vs* +Help: error({str}*): abort script with error message str. +Description: + (error):void pari_err(0, $1) + (?gen,...):void pari_err(e_MISC, "${2 format_string}"${2 format_args}) +Doc: outputs its argument list (each of + them interpreted as a string), then interrupts the running \kbd{gp} program, + returning to the input prompt. For instance + \bprog + error("n = ", n, " is not squarefree!") + @eprog\noindent +Variant: + The variadic version \fun{void}{pari_err}{e_USER,...} is usually preferable. + +Function: eta +Class: basic +Section: transcendental +C-Name: eta0 +Prototype: GD0,L,p +Help: eta(z,{flag=0}): if flag=0, returns prod(n=1,oo, 1-q^n), where + q = exp(2 i Pi z) if z is a complex scalar (belonging to the upper half plane); + q = z if z is a p-adic number or can be converted to a power series. + If flag is nonzero, the function only applies to complex scalars and returns + the true eta function, with the factor q^(1/24) included. +Doc: Variants of \idx{Dedekind}'s $\eta$ function. + If $\fl = 0$, return $\prod_{n=1}^{\infty}(1-q^{n})$, where $q$ depends on $x$ + in the following way: + + \item $q = e^{2i\pi x}$ if $x$ is a \emph{complex number} (which must then + have positive imaginary part); notice that the factor $q^{1/24}$ is + missing! + + \item $q = x$ if $x$ is a \typ{PADIC}, or can be converted to a + \emph{power series} (which must then have positive valuation). + + If $\fl$ is nonzero, $x$ is converted to a complex number and we return the + true $\eta$ function, $q^{1/24}\prod_{n=1}^{\infty}(1-q^{n})$, + where $q = e^{2i\pi x}$. +Variant: + Also available is \fun{GEN}{trueeta}{GEN x, long prec} ($\fl=1$). + +Function: eulerfrac +Class: basic +Section: combinatorics +C-Name: eulerfrac +Prototype: L +Help: eulerfrac(n): Euler number E_n, as a rational number. +Doc: Euler number\sidx{Euler numbers} $E_{n}$, + where $E_{0}=1$, $E_{1}=0$, $E_{2}=-1$, \dots, are integers such that + $$ \dfrac{1}{\cosh t} = \sum_{n\geq 0} \dfrac{E_{n}}{n!} t^{n}. $$ + The argument $n$ should be a nonnegative integer. + \bprog + ? vector(10,i,eulerfrac(i)) + %1 = [0, -1, 0, 5, 0, -61, 0, 1385, 0, -50521] + ? eulerfrac(20000); + ? sizedigit(%)) + %3 = 73416 + @eprog + +Function: eulerianpol +Class: basic +Section: combinatorics +C-Name: eulerianpol +Prototype: LDn +Help: eulerianpol(n,{v='x}): Eulerian polynomial A_n, in variable v. +Doc: \idx{Eulerian polynomial} $A_{n}$ in variable $v$ defined by + $$ + \sum_{n=0}^{\infty} A_{n}(x) \dfrac{T^{n}}{n!} = \dfrac{x-1}{x-e^{(x-1)T}}. + $$ + \bprog + ? eulerianpol(2) + %1 = x + 1 + ? eulerianpol(5, 't) + %2 = t^4 + 26*t^3 + 66*t^2 + 26*t + 1 + @eprog + +Function: eulerphi +Class: basic +Section: number_theoretical +C-Name: eulerphi +Prototype: G +Help: eulerphi(x): Euler's totient function of x. +Description: + (gen):int eulerphi($1) +Doc: Euler's $\phi$ (totient)\sidx{Euler totient function} function of the + integer $|x|$, in other words $|(\Z/x\Z)^{*}|$. + \bprog + ? eulerphi(40) + %1 = 16 + @eprog\noindent + According to this definition we let $\phi(0) := 2$, since $\Z^{*} = \{-1,1\}$; + this is consistent with \kbd{znstar(0)}: we have + \kbd{znstar$(n)$.no = eulerphi(n)} for all $n\in\Z$. + +Function: eulerpol +Class: basic +Section: combinatorics +C-Name: eulerpol +Prototype: LDn +Help: eulerpol(n,{v='x}): Euler polynomial E_n, in variable v. +Doc: \idx{Euler polynomial} $E_{n}$ in variable $v$ defined by + $$ + \sum_{n=0}^{\infty} E_{n}(x)\dfrac{T^{n}}{n!} = \dfrac{2e^{xT}}{e^{T}+1}. + $$ + \bprog + ? eulerpol(1) + %1 = x - 1/2 + ? eulerpol(3) + %2 = x^3 - 3/2*x^2 + 1/4 + @eprog + +Function: eulerreal +Class: basic +Section: combinatorics +C-Name: eulerreal +Prototype: Lp +Help: eulerreal(n): Euler number E_n, as a real number. +Doc: Euler number\sidx{Euler numbers} $E_{n}$, + where $E_{0}=1$, $E_{1}=0$, $E_{2}=-1$, \dots, are integers such that + $$ \dfrac{1}{\cosh t} = \sum_{n\geq 0} \dfrac{E_{n}}{n!} t^{n}. $$ + The argument $n$ should be a nonnegative integer. Return $E_{n}$ + as a real number (with the current precision). + \bprog + ? sizedigit(eulerfrac(20000)) + %1 = 73416 + ? eulerreal(20000); + %2 = 9.2736664576330851823546169139003297830 E73414 + @eprog + +Function: eulervec +Class: basic +Section: combinatorics +C-Name: eulervec +Prototype: L +Help: eulervec(n): returns a vector containing + the nonzero Euler numbers E_0, E_2, ..., E_{2n}. +Doc: returns a vector containing the nonzero \idx{Euler numbers} $E_{0}$, + $E_{2}$,\dots, $E_{2n}$: + \bprog + ? eulervec(5) \\ E_0, E_2..., E_10 + %1 = [1, -1, 5, -61, 1385, -50521] + ? eulerfrac(10) + %2 = -50521 + @eprog\noindent This routine uses more memory but is faster than + repeated calls to \kbd{eulerfrac}: + \bprog + ? forstep(n = 2, 8000, 2, eulerfrac(n)) + time = 27,3801ms. + ? eulervec(4000); + time = 8,430 ms. + @eprog + The computed Euler numbers are stored in an incremental + cache which makes later calls to \kbd{eulerfrac} and \kbd{eulerreal} + instantaneous in the cache range: re-running the same previous \kbd{eulerfrac}s + after the \kbd{eulervec} call gives: + \bprog + ? forstep(n = 2, 10000, 2, eulerfrac(n)) + time = 0 ms. + @eprog + +Function: eval +Class: basic +Section: polynomials +C-Name: geval_gp +Prototype: GC +Help: eval(x): evaluation of x, replacing variables by their value. +Description: + (gen):gen geval($1) +Doc: replaces in $x$ the formal variables by the values that + have been assigned to them after the creation of $x$. This is mainly useful + in GP, and not in library mode. Do not confuse this with substitution (see + \kbd{subst}). + + If $x$ is a character string, \kbd{eval($x$)} executes $x$ as a GP + command, as if directly input from the keyboard, and returns its + output. + \bprog + ? x1 = "one"; x2 = "two"; + ? n = 1; eval(Str("x", n)) + %2 = "one" + ? f = "exp"; v = 1; + ? eval(Str(f, "(", v, ")")) + %4 = 2.7182818284590452353602874713526624978 + @eprog\noindent Note that the first construct could be implemented in a + simpler way by using a vector \kbd{x = ["one","two"]; x[n]}, and the second + by using a closure \kbd{f = exp; f(v)}. The final example is more interesting: + \bprog + ? genmat(u,v) = matrix(u,v,i,j, eval( Str("x",i,j) )); + ? genmat(2,3) \\ generic 2 x 3 matrix + %2 = + [x11 x12 x13] + + [x21 x22 x23] + @eprog + + A syntax error in the evaluation expression raises an \kbd{e\_SYNTAX} + exception, which can be trapped as usual: + \bprog + ? 1a + *** syntax error, unexpected variable name, expecting $end or ';': 1a + *** ^- + ? E(expr) = + { + iferr(eval(expr), + e, print("syntax error"), + errname(e) == "e_SYNTAX"); + } + ? E("1+1") + %1 = 2 + ? E("1a") + syntax error + @eprog + \synt{geval}{GEN x}. + +Function: exp +Class: basic +Section: transcendental +C-Name: gexp +Prototype: Gp +Help: exp(x): exponential of x. +Description: + (real):real mpexp($1) + (mp):real:prec gexp($1, $prec) + (gen):gen:prec gexp($1, $prec) +Doc: exponential of $x$. + $p$-adic arguments with positive valuation are accepted. +Variant: For a \typ{PADIC} $x$, the function + \fun{GEN}{Qp_exp}{GEN x} is also available. + +Function: expm1 +Class: basic +Section: transcendental +C-Name: gexpm1 +Prototype: Gp +Help: expm1(x): exp(x)-1. +Description: + (real):real mpexpm1($1) +Doc: return $\exp(x)-1$, computed in a way that is also accurate + when the real part of $x$ is near $0$. + A naive direct computation would suffer from catastrophic cancellation; + PARI's direct computation of $\exp(x)$ alleviates this well known problem at + the expense of computing $\exp(x)$ to a higher accuracy when $x$ is small. + Using \kbd{expm1} is recommended instead: + \bprog + ? default(realprecision, 10000); x = 1e-100; + ? a = expm1(x); + time = 4 ms. + ? b = exp(x)-1; + time = 4 ms. + ? default(realprecision, 10040); x = 1e-100; + ? c = expm1(x); \\ reference point + ? abs(a-c)/c \\ relative error in expm1(x) + %7 = 1.4027986153764843997 E-10019 + ? abs(b-c)/c \\ relative error in exp(x)-1 + %8 = 1.7907031188259675794 E-9919 + @eprog\noindent As the example above shows, when $x$ is near $0$, + \kbd{expm1} is more accurate than \kbd{exp(x)-1}. + +Function: exponent +Class: basic +Section: conversions +C-Name: gpexponent +Prototype: G +Help: exponent(x): binary exponent of x +Doc: When $x$ is a \typ{REAL}, the result is the binary exponent $e$ of $x$. + For a nonzero $x$, this is the unique integer $e$ such that + $2^{e} \leq |x| < 2^{e+1}$. For a real $0$, this returns the PARI exponent $e$ + attached to $x$ (which may represent any floating-point number less than + $2^{e}$ in absolute value). + \bprog + ? exponent(Pi) + %1 = 1 + ? exponent(4.0) + %2 = 2 + ? exponent(0.0) + %3 = -128 + ? default(realbitprecision) + %4 = 128 + @eprog\noindent This definition extends naturally to nonzero integers, + and the exponent of an exact $0$ is $-\kbd{oo}$ by convention. + + For convenience, we \emph{define} the exponent of a \typ{FRAC} $a/b$ as + the difference of \kbd{exponent}$(a)$ and \kbd{exponent}$(b)$; note that, + if $e'$ denotes the exponent of \kbd{$a/b$ * 1.0}, then the exponent $e$ + we return is either $e'$ or $e'+1$, thus $2^{e+1}$ is an upper bound for + $|a/b|$. + \bprog + ? [ exponent(9), exponent(10), exponent(9/10), exponent(9/10*1.) ] + %5 = [3, 3, 0, -1] + @eprog + + For a PARI object of type \typ{COMPLEX}, \typ{POL}, \typ{SER}, \typ{VEC}, + \typ{COL}, \typ{MAT} this returns the largest exponent found among the + components of $x$. Hence $2^{e+1}$ is a quick upper bound for the sup norm + of real matrices or polynomials; and $2^{e+(3/2)}$ for complex ones. + + \bprog + ? exponent(3*x^2 + 15*x - 100) + %5 = 6 + ? exponent(0) + %6 = -oo + @eprog +Variant: + Also available is \fun{long}{gexpo}{GEN x}. + +Function: export +Class: basic +Section: programming/specific +Help: export(x{=...},...,z{=...}): export the variables x,...,z to the parallel world. +Doc: Export the variables $x,\ldots, z$ to the parallel world. + Such variables are visible inside parallel sections in place of global + variables, but cannot be modified inside a parallel section. + \kbd{export(a)} set the variable $a$ in the parallel world to current value of $a$. + \kbd{export(a=z)} set the variable $a$ in the parallel world to $z$, without + affecting the current value of $a$. + \bprog + ? fun(x)=x^2+1; + ? parvector(10,i,fun(i)) + *** mt: please use export(fun). + ? export(fun) + ? parvector(10,i,fun(i)) + %4 = [2,5,10,17,26,37,50,65,82,101] + @eprog + +Function: exportall +Class: basic +Section: programming/specific +C-Name: exportall +Prototype: v +Help: exportall(): declare all current dynamic variables as exported variables. +Doc: declare all current dynamic variables as exported variables. + Such variables are visible inside parallel sections in place of global variables. + \bprog + ? fun(x)=x^2+1; + ? parvector(10,i,fun(i)) + *** mt: please use export(fun). + ? exportall() + ? parvector(10,i,fun(i)) + %4 = [2,5,10,17,26,37,50,65,82,101] + @eprog + +Function: extern +Class: basic +Section: programming/specific +C-Name: gpextern +Prototype: s +Help: extern(str): execute shell command str, and feeds the result to GP (as + if loading from file). +Doc: the string \var{str} is the name of an external command (i.e.~one you + would type from your UNIX shell prompt). This command is immediately run and + its output fed into \kbd{gp}, just as if read from a file. + +Function: externstr +Class: basic +Section: programming/specific +C-Name: externstr +Prototype: s +Help: externstr(str): execute shell command str, and returns the result as a + vector of GP strings, one component per output line. +Doc: the string \var{str} is the name of an external command (i.e.~one you + would type from your UNIX shell prompt). This command is immediately run and + its output is returned as a vector of GP strings, one component per output + line. + +Function: factor +Class: basic +Section: number_theoretical +C-Name: factor0 +Prototype: GDG +Help: factor(x,{D}): factorization of x over domain D. If x and D are both + integers, return partial factorization, using primes < D. +Description: + (int):vec Z_factor($1) + (int,):vec Z_factor($1) + (int,small):vec Z_factor_limit($1, $2) + (gen):vec factor($1) + (gen,):vec factor($1) + (gen,gen):vec factor0($1, $2) +Doc: factor $x$ over domain $D$; if $D$ is omitted, it is determined from $x$. + For instance, if $x$ is an integer, it is factored in $\Z$, if it is a + polynomial with rational coefficients, it is factored in $\Q[x]$, etc., see + below for details. The result is a two-column matrix: the first contains the + irreducibles dividing $x$ (rational or Gaussian primes, irreducible + polynomials), and the second the exponents. By convention, $0$ is factored + as $0^{1}$. + + \misctitle{$x \in \Q$} + See \tet{factorint} for the algorithms used. The factorization includes the + unit $-1$ when $x < 0$ and all other factors are positive; a denominator is + factored with negative exponents. The factors are sorted in increasing order. + \bprog + ? factor(-7/106) + %1 = + [-1 1] + + [ 2 -1] + + [ 7 1] + + [53 -1] + @eprog\noindent By convention, $1$ is factored as \kbd{matrix(0,2)} + (the empty factorization, printed as \kbd{[;]}). + + Large rational ``primes'' $ > 2^{64}$ in the factorization are in fact + \var{pseudoprimes} (see \kbd{ispseudoprime}), a priori not rigorously proven + primes. Use \kbd{isprime} to prove primality of these factors, as in + \bprog + ? fa = factor(2^2^7 + 1) + %2 = + [59649589127497217 1] + + [5704689200685129054721 1] + + ? isprime( fa[,1] ) + %3 = [1, 1]~ \\ both entries are proven primes + @eprog\noindent + Another possibility is to globally set the default \tet{factor_proven}, which + will perform a rigorous primality proof for each pseudoprime factor but will + slow down PARI. + + A \typ{INT} argument $D$ can be added, meaning that we only trial divide + by all primes $p < D$ and the \kbd{addprimes} entries, then skip all + expensive factorization methods. The limit $D$ must be nonnegative. + In this case, one entry in the factorization may be a composite number: all + factors less than $D^{2}$ and primes from the \kbd{addprimes} table + are actual primes. But (at most) one entry may not verify this criterion, + and it may be prime or composite: it is only known to be coprime to all + other entries and not a pure power. + + \bprog + ? factor(2^2^7 +1, 10^5) + %4 = + [340282366920938463463374607431768211457 1] + @eprog\noindent + \misctitle{Deprecated feature} Setting $D=0$ is the same + as setting it to $\kbd{factorlimit} + 1$. + \smallskip + + This routine uses trial division and perfect power tests, and should not be + used for huge values of $D$ (at most $10^{9}$, say): + \kbd{factorint(, 1 + 8)} will in general be faster. The latter does not + guarantee that all small prime factors are found, but it also finds larger + factors and in a more efficient way. + \bprog + ? F = (2^2^7 + 1) * 1009 * (10^5+3); factor(F, 10^5) \\ fast, incomplete + time = 0 ms. + %5 = + [1009 1] + + [34029257539194609161727850866999116450334371 1] + + ? factor(F, 10^9) \\ slow + time = 3,260 ms. + %6 = + [1009 1] + + [100003 1] + + [340282366920938463463374607431768211457 1] + + ? factorint(F, 1+8) \\ much faster and all small primes were found + time = 8 ms. + %7 = + [1009 1] + + [100003 1] + + [340282366920938463463374607431768211457 1] + + ? factor(F) \\ complete factorization + time = 60 ms. + %8 = + [1009 1] + + [100003 1] + + [59649589127497217 1] + + [5704689200685129054721 1] + @eprog + + \misctitle{$x \in \Q(i)$} The factorization is performed with Gaussian + primes in $\Z[i]$ and includes Gaussian units in $\{\pm1, \pm i\}$; + factors are sorted by increasing norm. Except for a possible leading unit, + the Gaussian factors are normalized: rational factors are positive and + irrational factors have positive imaginary part. + + Unless \tet{factor_proven} is set, large factors are actually pseudoprimes, + not proven primes; a rational factor is prime if less than $2^{64}$ and an + irrational one if its norm is less than $2^{64}$. + \bprog + ? factor(5*I) + %9 = + [ 2 + I 1] + + [1 + 2*I 1] + @eprog\noindent One can force the factorization of a rational number + by setting the domain $D = I$: + \bprog + ? factor(-5, I) + %10 = + [ I 1] + + [ 2 + I 1] + + [1 + 2*I 1] + ? factorback(%) + %11 = -5 + @eprog + + \misctitle{Univariate polynomials and rational functions} + PARI can factor univariate polynomials in $K[t]$. The following base fields + $K$ are currently supported: $\Q$, $\R$, $\C$, $\Q_{p}$, finite fields and + number fields. See \tet{factormod} and \tet{factorff} for the algorithms used + over finite fields and \tet{nffactor} for the algorithms over number fields. + The irreducible factors are sorted by increasing degree and normalized: they + are monic except when $K = \Q$ where they are primitive in $\Z[t]$. + + The content is \emph{not} included in the factorization, in particular + \kbd{factorback} will in general recover the original $x$ only up to + multiplication by an element of $K^{*}$: when $K\neq\Q$, this scalar is + \kbd{pollead}$(x)$ (since irreducible factors are monic); and when $K = \Q$ + you can either ask for the $\Q$-content explicitly of use factorback: + \bprog + ? P = t^2 + 5*t/2 + 1; F = factor(P) + %12 = + [t + 2 1] + + [2*t + 1 1] + + ? content(P, 1) \\ Q-content + %13 = 1/2 + + ? pollead(factorback(F)) / pollead(P) + %14 = 2 + @eprog + + You can specify $K$ using the optional ``domain'' argument $D$ as follows + + \item $K = \Q$ : $D$ a rational number (\typ{INT} or \typ{FRAC}), + + \item $K = \Z/p\Z$ with $p$ prime : $D$ a \typ{INTMOD} modulo $p$; + factoring modulo a composite number is not supported. + + \item $K = \F_{q}$ : $D$ a \typ{FFELT} encoding the finite field; you can also + use a \typ{POLMOD} of \typ{INTMOD} modulo a prime $p$ but this is usualy + less convenient; + + \item $K = \Q[X]/(T)$ a number field : $D$ a \typ{POLMOD} modulo $T$, + + \item $K = \Q(i)$ (alternate syntax for special case): $D = I$, + + \item $K = \Q(w)$ a quadratic number field (alternate syntax for special + case): $D$ a \typ{QUAD}, + + \item $K = \R$ : $D$ a real number (\typ{REAL}); truncate the factorization + at accuracy \kbd{precision}$(D)$. If $x$ is inexact and \kbd{precision}$(x)$ + is less than \kbd{precision}$(D)$, then the precision of $x$ is used instead. + + \item $K = \C$ : $D$ a complex number with a \typ{REAL} component, e.g. + \kbd{I * 1.}; truncate the factorization as for $K = \R$, + + \item $K = \Q_{p}$ : $D$ a \typ{PADIC}; truncate the factorization at + $p$-adic accuracy \kbd{padicprec}$(D)$, possibly less if $x$ is inexact + with insufficient $p$-adic accuracy; + + \bprog + ? T = x^2+1; + ? factor(T, 1); \\ over Q + ? factor(T, Mod(1,3)) \\ over F_3 + ? factor(T, ffgen(ffinit(3,2,'t))^0) \\ over F_{3^2} + ? factor(T, Mod(Mod(1,3), t^2+t+2)) \\ over F_{3^2}, again + ? factor(T, O(3^6)) \\ over Q_3, precision 6 + ? factor(T, 1.) \\ over R, current precision + ? factor(T, I*1.) \\ over C + ? factor(T, Mod(1, y^3-2)) \\ over Q(2^{1/3}) + @eprog\noindent In most cases, it is possible and simpler to call a + specialized variant rather than use the above scheme: + \bprog + ? factormod(T, 3) \\ over F_3 + ? factormod(T, [t^2+t+2, 3]) \\ over F_{3^2} + ? factormod(T, ffgen(3^2, 't)) \\ over F_{3^2} + ? factorpadic(T, 3,6) \\ over Q_3, precision 6 + ? nffactor(y^3-2, T) \\ over Q(2^{1/3}) + ? polroots(T) \\ over C + ? polrootsreal(T) \\ over R (real polynomial) + @eprog + + It is also possible to let the routine use the smallest field containing all + coefficients, taking into account quotient structures induced by + \typ{INTMOD}s and \typ{POLMOD}s (e.g.~if a coefficient in $\Z/n\Z$ is known, + all rational numbers encountered are first mapped to $\Z/n\Z$; different + moduli will produce an error): + \bprog + ? T = x^2+1; + ? factor(T); \\ over Q + ? factor(T*Mod(1,3)) \\ over F_3 + ? factor(T*ffgen(ffinit(3,2,'t))^0) \\ over F_{3^2} + ? factor(T*Mod(Mod(1,3), t^2+t+2)) \\ over F_{3^2}, again + ? factor(T*(1 + O(3^6)) \\ over Q_3, precision 6 + ? factor(T*1.) \\ over R, current precision + ? factor(T*(1.+0.*I)) \\ over C + ? factor(T*Mod(1, y^3-2)) \\ over Q(2^{1/3}) + @eprog\noindent Multiplying by a suitable field element equal to $1 \in K$ + in this way is error-prone and is not recommanded. Factoring existing + polynomials with obvious fields of coefficients is fine, the domain + argument $D$ should be used instead ad hoc conversions. + + \misctitle{Note on inexact polynomials} + Polynomials with inexact coefficients + (e.g. floating point or $p$-adic numbers) + are first rounded to an exact representation, then factored to (potentially) + infinite accuracy and we return a truncated approximation of that + virtual factorization. To avoid pitfalls, we advise to only factor + \emph{exact} polynomials: + \bprog + ? factor(x^2-1+O(2^2)) \\ rounded to x^2 + 3, irreducible in Q_2 + %1 = + [(1 + O(2^2))*x^2 + O(2^2)*x + (1 + 2 + O(2^2)) 1] + + ? factor(x^2-1+O(2^3)) \\ rounded to x^2 + 7, reducible ! + %2 = + [ (1 + O(2^3))*x + (1 + 2 + O(2^3)) 1] + + [(1 + O(2^3))*x + (1 + 2^2 + O(2^3)) 1] + + ? factor(x^2-1, O(2^2)) \\ no ambiguity now + %3 = + [ (1 + O(2^2))*x + (1 + O(2^2)) 1] + + [(1 + O(2^2))*x + (1 + 2 + O(2^2)) 1] + @eprog + + \misctitle{Note about inseparable polynomials} Polynomials with inexact + coefficients are considered to be squarefree: indeed, there exist a + squarefree polynomial arbitrarily close to the input, and they cannot be + distinguished at the input accuracy. This means that irreducible factors are + repeated according to their apparent multiplicity. On the contrary, using a + specialized function such as \kbd{factorpadic} with an \emph{exact} rational + input yields the correct multiplicity when the (now exact) input is not + separable. Compare: + \bprog + ? factor(z^2 + O(5^2))) + %1 = + [(1 + O(5^2))*z + O(5^2) 1] + + [(1 + O(5^2))*z + O(5^2) 1] + ? factor(z^2, O(5^2)) + %2 = + [1 + O(5^2))*z + O(5^2) 2] + @eprog + + \misctitle{Multivariate polynomials and rational functions} + PARI recursively factors \emph{multivariate} polynomials in + $K[t_{1},\dots, t_{d}]$ for the same fields $K$ as above and the argument $D$ + is used in the same way to specify $K$. The irreducible factors are sorted + by their main variable (least priority first) then by increasing degree. + + \bprog + ? factor(x^2 + y^2, Mod(1,5)) + %1 = + [ x + Mod(2, 5)*y 1] + + [Mod(1, 5)*x + Mod(3, 5)*y 1] + + ? factor(x^2 + y^2, O(5^2)) + %2 = + [ (1 + O(5^2))*x + (O(5^2)*y^2 + (2 + 5 + O(5^2))*y + O(5^2)) 1] + + [(1 + O(5^2))*x + (O(5^2)*y^2 + (3 + 3*5 + O(5^2))*y + O(5^2)) 1] + + ? lift(%) + %3 = + [ x + 7*y 1] + + [x + 18*y 1] + @eprog\noindent Note that the implementation does not really support inexact + real fields ($\R$ or $\C$) and usually misses factors even if the input + is exact: + \bprog + ? factor(x^2 + y^2, I) \\ over Q(i) + %4 = + [x - I*y 1] + + [x + I*y 1] + + ? factor(x^2 + y^2, I*1.) \\ over C + %5 = + [x^2 + y^2 1] + @eprog +Variant: + \fun{GEN}{factor}{GEN x} + \fun{GEN}{boundfact}{GEN x, ulong lim}. + +Function: factorback +Class: basic +Section: number_theoretical +C-Name: factorback2 +Prototype: GDG +Help: factorback(f,{e}): given a factorization f, gives the factored + object back. If e is present, f has to be a vector of the same length, and + we return the product of the f[i]^e[i]. +Description: + (gen):gen factorback($1) + (gen,):gen factorback($1) + (gen,gen):gen factorback2($1, $2) +Doc: gives back the factored object corresponding to a factorization. The + integer $1$ corresponds to the empty factorization. + + If $e$ is present, $e$ and $f$ must be vectors of the same length ($e$ being + integral), and the corresponding factorization is the product of the + $f[i]^{e[i]}$. + + If not, and $f$ is vector, it is understood as in the preceding case with $e$ + a vector of 1s: we return the product of the $f[i]$. Finally, $f$ can be a + regular factorization, as produced with any \kbd{factor} command. A few + examples: + \bprog + ? factor(12) + %1 = + [2 2] + + [3 1] + + ? factorback(%) + %2 = 12 + ? factorback([2,3], [2,1]) \\ 2^2 * 3^1 + %3 = 12 + ? factorback([5,2,3]) + %4 = 30 + @eprog +Variant: Also available is \fun{GEN}{factorback}{GEN f} (case $e = \kbd{NULL}$). + +Function: factorcantor +Class: basic +Section: number_theoretical +C-Name: factmod +Prototype: GG +Obsolete: 2018-02-28 +Help: factorcantor(x,p): this function is obsolete, use factormod. +Doc: this function is obsolete, use factormod. + +Function: factorff +Class: basic +Section: number_theoretical +C-Name: factorff +Prototype: GDGDG +Obsolete: 2018-03-11 +Help: factorff(x,{p},{a}): obsolete, use factormod. +Doc: obsolete, kept for backward compatibility: use factormod. + +Function: factorial +Class: basic +Section: number_theoretical +C-Name: mpfactr +Prototype: Lp +Help: factorial(x): factorial of x, the result being given as a real number. +Doc: factorial of $x$. The expression $x!$ gives a result which is an integer, + while $\kbd{factorial}(x)$ gives a real number. +Variant: \fun{GEN}{mpfact}{long x} returns $x!$ as a \typ{INT}. + +Function: factorint +Class: basic +Section: number_theoretical +C-Name: factorint +Prototype: GD0,L, +Help: factorint(x,{flag=0}): factor the integer x. flag is optional, whose + binary digits mean 1: avoid MPQS, 2: avoid first-stage ECM (may fall back on + it later), 4: avoid Pollard-Brent Rho and Shanks SQUFOF, 8: skip final ECM + (huge composites will be declared prime). +Doc: factors the integer $n$ into a product of + pseudoprimes (see \kbd{ispseudoprime}), using a combination of the + \idx{Shanks SQUFOF} and \idx{Pollard Rho} method (with modifications due to + Brent), \idx{Lenstra}'s \idx{ECM} (with modifications by Montgomery), and + \idx{MPQS} (the latter adapted from the \idx{LiDIA} code with the kind + permission of the LiDIA maintainers), as well as a search for pure powers. + The output is a two-column matrix as for \kbd{factor}: the first column + contains the ``prime'' divisors of $n$, the second one contains the + (positive) exponents. + + By convention $0$ is factored as $0^{1}$, and $1$ as the empty factorization; + also the divisors are by default not proven primes if they are larger than + $2^{64}$, they only failed the BPSW compositeness test (see + \tet{ispseudoprime}). Use \kbd{isprime} on the result if you want to + guarantee primality or set the \tet{factor_proven} default to $1$. + Entries of the private prime tables (see \tet{addprimes}) are also included + as is. + + This gives direct access to the integer factoring engine called by most + arithmetical functions. \fl\ is optional; its binary digits mean 1: avoid + MPQS, 2: skip first stage ECM (we may still fall back to it later), 4: avoid + Rho and SQUFOF, 8: don't run final ECM (as a result, a huge composite may be + declared to be prime). Note that a (strong) probabilistic primality test is + used; thus composites might not be detected, although no example is known. + + You are invited to play with the flag settings and watch the internals at + work by using \kbd{gp}'s \tet{debug} default parameter (level 3 shows + just the outline, 4 turns on time keeping, 5 and above show an increasing + amount of internal details). + +Function: factormod +Class: basic +Section: number_theoretical +C-Name: factormod0 +Prototype: GDGD0,L, +Help: factormod(f,{D},{flag=0}): factors the polynomial f over the finite + field defined by the domain D; flag is optional, and can be + 0: default or 1: only the degrees of the irreducible factors are given. +Doc: factors the polynomial $f$ over the finite field defined by the domain + $D$ as follows: + + \item $D = p$ a prime: factor over $\F_{p}$; + + \item $D = [T,p]$ for a prime $p$ and $T(y)$ an irreducible polynomial over + $\F_{p}$: factor over $\F_{p}[y]/(T)$ (as usual the main variable of $T$ must have + lower priority than the main variable of $f$); + + \item $D$ a \typ{FFELT}: factor over the attached field; + + \item $D$ omitted: factor over the field of definition of $f$, which + must be a finite field. + + The coefficients of $f$ must be operation-compatible with the corresponding + finite field. The result is a two-column matrix, the first column being the + irreducible polynomials dividing $f$, and the second the exponents. + By convention, the $0$ polynomial factors as $0^{1}$; a nonzero constant + polynomial has empty factorization, a $0\times 2$ matrix. The irreducible + factors are ordered by increasing degree and the result is canonical: it will + not change across multiple calls or sessions. + + \bprog + ? factormod(x^2 + 1, 3) \\ over F_3 + %1 = + [Mod(1, 3)*x^2 + Mod(1, 3) 1] + ? liftall( factormod(x^2 + 1, [t^2+1, 3]) ) \\ over F_9 + %2 = + [ x + t 1] + + [x + 2*t 1] + + \\ same, now letting GP choose a model + ? T = ffinit(3,2,'t) + %3 = Mod(1, 3)*t^2 + Mod(1, 3)*t + Mod(2, 3) + ? liftall( factormod(x^2 + 1, [T, 3]) ) + %4 = \\ t is a root of T ! + [ x + (t + 2) 1] + + [x + (2*t + 1) 1] + ? t = ffgen(t^2+Mod(1,3)); factormod(x^2 + t^0) \\ same using t_FFELT + %5 = + [ x + t 1] + + [x + 2*t 1] + ? factormod(x^2+Mod(1,3)) + %6 = + [Mod(1, 3)*x^2 + Mod(1, 3) 1] + ? liftall( factormod(x^2 + Mod(Mod(1,3), y^2+1)) ) + %7 = + [ x + y 1] + + [x + 2*y 1] + @eprog + + If $\fl$ is nonzero, outputs only the \emph{degrees} of the irreducible + polynomials (for example to compute an $L$-function). By convention, a + constant polynomial (including the $0$ polynomial) has empty factorization. + The degrees appear in increasing order but need not correspond to the + ordering with $\fl =0$ when multiplicities are present. + \bprog + ? f = x^3 + 2*x^2 + x + 2; + ? factormod(f, 5) \\ (x+2)^2 * (x+3) + %1 = + [Mod(1, 5)*x + Mod(2, 5) 2] + + [Mod(1, 5)*x + Mod(3, 5) 1] + ? factormod(f, 5, 1) \\ (deg 1) * (deg 1)^2 + %2 = + [1 1] + + [1 2] + @eprog + +Function: factormodDDF +Class: basic +Section: number_theoretical +C-Name: factormodDDF +Prototype: GDG +Help: factormodDDF(f,{D}): distinct-degree factorization of the + squarefree polynomial f over the finite field defined by the domain D. +Doc: distinct-degree factorization of the squarefree polynomial $f$ over the + finite field defined by the domain $D$ as follows: + + \item $D = p$ a prime: factor over $\F_{p}$; + + \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over + $\F_{p}$: factor over $\F_{p}[x]/(T)$; + + \item $D$ a \typ{FFELT}: factor over the attached field; + + \item $D$ omitted: factor over the field of definition of $f$, which + must be a finite field. + + If $f$ is not squarefree, the result is undefined. + The coefficients of $f$ must be operation-compatible with the corresponding + finite field. The result is a two-column matrix: + + \item the first column contains monic (squarefree, pairwise coprime) + polynomials dividing $f$, all of whose irreducible factors have + the same degree $d$; + + \item the second column contains the degrees of the irreducible factors. + + The factorization is ordered by increasing degree $d$ of irreducible factors, + and the result is obviously canonical. + This function is somewhat faster than full factorization. + + \bprog + ? f = (x^2 + 1) * (x^2-1); + ? factormodSQF(f,3) \\ squarefree over F_3 + %2 = + [Mod(1, 3)*x^4 + Mod(2, 3) 1] + + ? factormodDDF(f, 3) + %3 = + [Mod(1, 3)*x^2 + Mod(2, 3) 1] \\ two degree 1 factors + + [Mod(1, 3)*x^2 + Mod(1, 3) 2] \\ irred of degree 2 + + ? for(i=1,10^5,factormodDDF(f,3)) + time = 424 ms. + ? for(i=1,10^5,factormod(f,3)) \\ full factorization is a little slower + time = 464 ms. + + ? liftall( factormodDDF(x^2 + 1, [3, t^2+1]) ) \\ over F_9 + %6 = + [x^2 + 1 1] \\ product of two degree 1 factors + + ? t = ffgen(t^2+Mod(1,3)); factormodDDF(x^2 + t^0) \\ same using t_FFELT + %7 = + [x^2 + 1 1] + + ? factormodDDF(x^2-Mod(1,3)) + %8 = + [Mod(1, 3)*x^2 + Mod(2, 3) 1] + + @eprog + +Function: factormodSQF +Class: basic +Section: number_theoretical +C-Name: factormodSQF +Prototype: GDG +Help: factormodSQF(f,{D}): squarefree factorization of the polynomial f over + the finite field defined by the domain D. +Doc: squarefree factorization of the polynomial $f$ over the finite field + defined by the domain $D$ as follows: + + \item $D = p$ a prime: factor over $\F_{p}$; + + \item $D = [T,p]$ for a prime $p$ and $T$ an irreducible polynomial over + $\F_{p}$: factor over $\F_{p}[x]/(T)$; + + \item $D$ a \typ{FFELT}: factor over the attached field; + + \item $D$ omitted: factor over the field of definition of $f$, which + must be a finite field. + + The coefficients of $f$ must be operation-compatible with the corresponding + finite field. The result is a two-column matrix: + + \item the first column contains monic squarefree pairwise coprime polynomials + dividing $f$; + + \item the second column contains the power to which the polynomial in column + $1$ divides $f$; + + This is somewhat faster than full factorization. The factors are ordered by + increasing exponent and the result is obviously canonical. + + \bprog + ? f = (x^2 + 1)^3 * (x^2-1)^2; + ? factormodSQF(f, 3) \\ over F_3 + %1 = + [Mod(1, 3)*x^2 + Mod(2, 3) 2] + + [Mod(1, 3)*x^2 + Mod(1, 3) 3] + + ? for(i=1,10^5,factormodSQF(f,3)) + time = 192 ms. + ? for(i=1,10^5,factormod(f,3)) \\ full factorization is slower + time = 409 ms. + + ? liftall( factormodSQF((x^2 + 1)^3, [3, t^2+1]) ) \\ over F_9 + %4 = + [x^2 + 1 3] + + ? t = ffgen(t^2+Mod(1,3)); factormodSQF((x^2 + t^0)^3) \\ same using t_FFELT + %5 = + [x^2 + 1 3] + + ? factormodSQF(x^8 + x^7 + x^6 + x^2 + x + Mod(1,2)) + %6 = + [ Mod(1, 2)*x + Mod(1, 2) 2] + + [Mod(1, 2)*x^2 + Mod(1, 2)*x + Mod(1, 2) 3] + @eprog + +Function: factormodcyclo +Class: basic +Section: number_theoretical +C-Name: factormodcyclo +Prototype: LGD0,L,Dn +Help: factormodcyclo(n,p,{single=0},{v='x}): factor n-th + cyclotomic polynomial mod p. +Doc: Factors $n$-th cyclotomic polynomial $\Phi_{n}(x)$ mod $p$, + where $p$ is a prime number not dividing $n$. + Much faster than \kbd{factormod(polcyclo(n), p)}; the irreducible + factors should be identical and given in the same order. + If \var{single} is set, return a single irreducible factor; else (default) + return all the irreducible factors. Note that repeated calls of this + function with the \var{single} flag set may return different results because + the algorithm is probabilistic. Algorithms used are as follows. + + Let $F=\Q(\zeta_{n})$. Let $K$ be the splitting field of $p$ in $F$ and $e$ the + conductor of $K$. Then $\Phi_{n}(x)$ and $\Phi_{e}(x)$ have the same + number of irreducible factors mod $p$ and there is a simple algorithm + constructing irreducible factors of $\Phi_{n}(x)$ from irreducible + factors of $\Phi_{e}(x)$. So we may assume $n$ is equal to the + conductor of $K$. + Let $d$ be the order of $p$ in $(\Z/n\Z)^{\times}$ and $\varphi(n)=df$. + Then $\Phi_{n}(x)$ has $f$ irreducible factors $g_{i}(x)\;(1\leq i\leq f)$ + of degree $d$ over $\F_{p}$ or $\Z_{p}$. + + \item If $d$ is small, then we factor $g_{i}(x)$ into + $d$ linear factors $g_{ij}(x)$, $1\leq j\leq d$ in $\F_{q}[x]\;(q=p^{d})$ and + construct $G_{i}(x)=\prod_{j=1}^{d} g_{ij}(x)\in \F_{q}[x]$. + Then $G_{i}(x)\in\F_{p}[x]$ and $g_{i}(x)=G_{i}(x)$. + + \item If $f$ is small, then we work in $K$, which is a Galois extension of + degree $f$ over $\Q$. The Gaussian period + $\theta_{k}=\text{Tr}_{F/K}(\zeta_{n}^{k})$ is a sum of $k$-th power of roots + of $g_{i}(x)$ and $K=\Q(\theta_{1})$. + + Now, for each $k$, there is a polynomial $T_{k}(x)\in\Q[x]$ satisfying + $\theta_{k}=T_{k}(\theta_{1})$ because all $\theta_{k}$ are in $K$. Let + $T(x)\in\Z[x]$ be the minimal polynomial of $\theta_{1}$ over $\Q$. We get + $\theta_{1}$ mod $p$ from $T(x)$ and construct $\theta_{1},\cdots,\theta_{d}$ + mod $p$ using $T_{k}(x)$. Finally we recover $g_{i}(x)$ from + $\theta_{1},\cdots,\theta_{d}$ by Newton's formula. + + \bprog + ? lift(factormodcyclo(15, 11)) + %1 = [x^2 + 9*x + 4, x^2 + 4*x + 5, x^2 + 3*x + 9, x^2 + 5*x + 3] + ? factormodcyclo(15, 11, 1) \\ single + %2 = Mod(1, 11)*x^2 + Mod(5, 11)*x + Mod(3, 11) + ? z1 = lift(factormod(polcyclo(12345),11311)[,1]); + time = 32,498 ms. + ? z2 = factormodcyclo(12345,11311); + time = 47 ms. + ? z1 == z2 + %4 = 1 + @eprog + +Function: factornf +Class: basic +Section: number_fields +C-Name: polfnf +Prototype: GG +Obsolete: 2016-08-08 +Help: factornf(x,t): this function is obsolete, use nffactor. +Doc: This function is obsolete, use \kbd{nffactor}. + + factorization of the univariate polynomial $x$ + over the number field defined by the (univariate) polynomial $t$. $x$ may + have coefficients in $\Q$ or in the number field. The algorithm reduces to + factorization over $\Q$ (\idx{Trager}'s trick). The direct approach of + \tet{nffactor}, which uses \idx{van Hoeij}'s method in a relative setting, is + in general faster. + + The main variable of $t$ must be of \emph{lower} priority than that of $x$ + (see \secref{se:priority}). However if nonrational number field elements + occur (as polmods or polynomials) as coefficients of $x$, the variable of + these polmods \emph{must} be the same as the main variable of $t$. For + example + + \bprog + ? factornf(x^2 + Mod(y, y^2+1), y^2+1); + ? factornf(x^2 + y, y^2+1); \\@com these two are OK + ? factornf(x^2 + Mod(z,z^2+1), y^2+1) + *** at top-level: factornf(x^2+Mod(z,z + *** ^-------------------- + *** factornf: inconsistent data in rnf function. + ? factornf(x^2 + z, y^2+1) + *** at top-level: factornf(x^2+z,y^2+1 + *** ^-------------------- + *** factornf: incorrect variable in rnf function. + @eprog + +Function: factorpadic +Class: basic +Section: polynomials +C-Name: factorpadic +Prototype: GGL +Help: factorpadic(pol,p,r): p-adic factorization of the polynomial pol + to precision r. +Doc: $p$-adic factorization + of the polynomial \var{pol} to precision $r$, the result being a + two-column matrix as in \kbd{factor}. Note that this is not the same + as a factorization over $\Z/p^{r}\Z$ (polynomials over that ring do not form a + unique factorization domain, anyway), but approximations in $\Q/p^{r}\Z$ of + the true factorization in $\Q_{p}[X]$. + \bprog + ? factorpadic(x^2 + 9, 3,5) + %1 = + [(1 + O(3^5))*x^2 + O(3^5)*x + (3^2 + O(3^5)) 1] + ? factorpadic(x^2 + 1, 5,3) + %2 = + [ (1 + O(5^3))*x + (2 + 5 + 2*5^2 + O(5^3)) 1] + + [(1 + O(5^3))*x + (3 + 3*5 + 2*5^2 + O(5^3)) 1] + @eprog\noindent + The factors are normalized so that their leading coefficient is a power of + $p$. The method used is a modified version of the \idx{round 4} algorithm of + \idx{Zassenhaus}. + + If \var{pol} has inexact \typ{PADIC} coefficients, this is not always + well-defined; in this case, the polynomial is first made integral by dividing + out the $p$-adic content, then lifted to $\Z$ using \tet{truncate} + coefficientwise. + Hence we actually factor exactly a polynomial which is only $p$-adically + close to the input. To avoid pitfalls, we advise to only factor polynomials + with exact rational coefficients. + + \synt{factorpadic}{GEN f,GEN p, long r} . The function \kbd{factorpadic0} is + deprecated, provided for backward compatibility. + +Function: ffcompomap +Class: basic +Section: number_theoretical +C-Name: ffcompomap +Prototype: GG +Help: ffcompomap(f,g): Let k, l, m be three finite fields and f a (partial) map + from l to m and g a partial map from k to l, return the (partial) map f o g + from k to m. +Doc: Let $k$, $l$, $m$ be three finite fields and $f$ a (partial) map from $l$ + to $m$ and $g$ a (partial) map from $k$ to $l$, return the (partial) map $f + \circ g$ from $k$ to $m$. + \bprog + a = ffgen([3,5],'a); b = ffgen([3,10],'b); c = ffgen([3,20],'c); + m = ffembed(a, b); n = ffembed(b, c); + rm = ffinvmap(m); rn = ffinvmap(n); + nm = ffcompomap(n,m); + ffmap(n,ffmap(m,a)) == ffmap(nm, a) + %5 = 1 + ffcompomap(rm, rn) == ffinvmap(nm) + %6 = 1 + @eprog + +Function: ffembed +Class: basic +Section: number_theoretical +C-Name: ffembed +Prototype: GG +Help: ffembed(a,b): given two elements a and b in finite fields, return a map + embedding the definition field of a to the definition field of b. +Doc: given two finite fields elements $a$ and $b$, return a \var{map} + embedding the definition field of $a$ to the definition field of $b$. + Assume that the latter contains the former. + \bprog + ? a = ffgen([3,5],'a); + ? b = ffgen([3,10],'b); + ? m = ffembed(a, b); + ? A = ffmap(m, a); + ? minpoly(A) == minpoly(a) + %5 = 1 + @eprog + +Function: ffextend +Class: basic +Section: number_theoretical +C-Name: ffextend +Prototype: GGDn +Help: ffextend(a,P,{v}): + extend the field K of definition of a by a root of the polynomial P, assumed + to be irreducible over K. Return [r, m] where r is a root of P in the + extension field L and m is a map from K to L, see \kbd{ffmap}. If v is given, + the variable name is used to display the generator of L, else the name of the + variable of P is used. +Doc: extend the field $K$ of definition of $a$ by a root of the polynomial + $P\in K[X]$ assumed to be irreducible over $K$. Return $[r, m]$ where $r$ + is a root of $P$ in the extension field $L$ and $m$ is a map from $K$ to $L$, + see \kbd{ffmap}. + If $v$ is given, the variable name is used to display the generator of $L$, + else the name of the variable of $P$ is used. + A generator of $L$ can be recovered using $b=ffgen(r)$. + The image of $P$ in $L[X]$ can be recovered using $PL=ffmap(m,P)$. + \bprog + ? a = ffgen([3,5],'a); + ? P = x^2-a; polisirreducible(P) + %2 = 1 + ? [r,m] = ffextend(a, P, 'b); + ? r + %3 = b^9+2*b^8+b^7+2*b^6+b^4+1 + ? subst(ffmap(m, P), x, r) + %4 = 0 + ? ffgen(r) + %5 = b + @eprog + +Function: fffrobenius +Class: basic +Section: number_theoretical +C-Name: fffrobenius +Prototype: GD1,L, +Help: fffrobenius(m,{n=1}): return the n-th power of the Frobenius map over + the field of definition of m. +Doc: return the $n$-th power of the Frobenius map over the field of definition + of $m$. + \bprog + ? a = ffgen([3,5],'a); + ? f = fffrobenius(a); + ? ffmap(f,a) == a^3 + %3 = 1 + ? g = fffrobenius(a, 5); + ? ffmap(g,a) == a + %5 = 1 + ? h = fffrobenius(a, 2); + ? h == ffcompomap(f,f) + %7 = 1 + @eprog + +Function: ffgen +Class: basic +Section: number_theoretical +C-Name: ffgen +Prototype: GDn +Help: ffgen(k,{v = 'x}): return a generator of the finite field k + (not necessarily a generator of its multiplicative group) as a t_FFELT. + k can be given by its order q, the pair [p,f] with q=p^f, by an irreducible + polynomial with t_INTMOD coefficients, or by a finite field element. + If v is given, the variable name is used to display g, else the variable of + the polynomial or finite field element, or x if only the order was given. +Doc: return a generator for the finite field $k$ as a \typ{FFELT}. + The field $k$ can be given by + + \item its order $q$ + + \item the pair $[p,f]$ where $q=p^{f}$ + + \item a monic irreducible polynomial with \typ{INTMOD} coefficients modulo a + prime. + + \item a \typ{FFELT} belonging to $k$. + + If \kbd{v} is given, the variable name is used to display $g$, else the + variable of the polynomial or the \typ{FFELT} is used, else $x$ is used. + For efficiency, the characteristic is not checked to be prime; similarly + if a polynomial is given, we do not check whether it is irreducible. + + When only the order is specified, the function uses the polynomial generated + by \kbd{ffinit} and is deterministic: two calls to the function with the + same parameters will always give the same generator. + + To obtain a multiplicative generator, call \kbd{ffprimroot} on the result + (which is randomized). Its minimal polynomial then gives a \emph{primitive} + polynomial, which can be used to redefine the finite field so that all + subsequent computations use the new primitive polynomial: + \bprog + ? g = ffgen(16, 't); + ? g.mod \\ recover the underlying polynomial. + %2 = t^4 + t^3 + t^2 + t + 1 + ? g.pol \\ lift g as a t_POL + %3 = t + ? g.p \\ recover the characteristic + %4 = 2 + ? fforder(g) \\ g is not a multiplicative generator + %5 = 5 + ? a = ffprimroot(g) \\ recover a multiplicative generator + %6 = t^3 + t^2 + t + ? fforder(a) + %7 = 15 + ? T = minpoly(a) \\ primitive polynomial + %8 = Mod(1, 2)*x^4 + Mod(1, 2)*x^3 + Mod(1, 2) + ? G = ffgen(T); \\ is now a multiplicative generator + ? fforder(G) + %10 = 15 + @eprog +Variant: + To create a generator for a prime finite field, the function + \fun{GEN}{p_to_GEN}{GEN p, long v} returns \kbd{ffgen(p,v)\^{}0}. + +Function: ffinit +Class: basic +Section: number_theoretical +C-Name: ffinit +Prototype: GLDn +Help: ffinit(p,n,{v='x}): monic irreducible polynomial of degree n in F_p[v]. +Description: + (int, small, ?var):pol ffinit($1, $2, $3) +Doc: computes a monic polynomial of degree $n$ which is irreducible over + $\F_{p}$, where $p$ is assumed to be prime. This function uses a fast variant + of Adleman and Lenstra's algorithm. + + It is useful in conjunction with \tet{ffgen}; for instance if + \kbd{P = ffinit(3,2)}, you can represent elements in $\F_{3^{2}}$ in term of + \kbd{g = ffgen(P,'t)}. This can be abbreviated as + \kbd{g = ffgen(3\pow2, 't)}, where the defining polynomial $P$ can be later + recovered as \kbd{g.mod}. + +Function: ffinvmap +Class: basic +Section: number_theoretical +C-Name: ffinvmap +Prototype: G +Help: ffinvmap(m): given a map m between finite fields, return a partial map + that return the pre-images by the map m. +Doc: $m$ being a map from $K$ to $L$ two finite fields, return the partial map + $p$ from $L$ to $K$ such that for all $k\in K$, $p(m(k))=k$. + \bprog + ? a = ffgen([3,5],'a); + ? b = ffgen([3,10],'b); + ? m = ffembed(a, b); + ? p = ffinvmap(m); + ? u = random(a); + ? v = ffmap(m, u); + ? ffmap(p, v^2+v+2) == u^2+u+2 + %7 = 1 + ? ffmap(p, b) + %8 = [] + @eprog + +Function: fflog +Class: basic +Section: number_theoretical +C-Name: fflog +Prototype: GGDG +Help: fflog(x,g,{o}): return the discrete logarithm of the finite field + element x in base g. If present, o must represent the multiplicative + order of g. If no o is given, assume that g is a primitive root. +Doc: discrete logarithm of the finite field element $x$ in base $g$, + i.e.~an $e$ in $\Z$ such that $g^{e} = o$. If + present, $o$ represents the multiplicative order of $g$, see + \secref{se:DLfun}; the preferred format for + this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord} is the + order of $g$. It may be set as a side effect of calling \tet{ffprimroot}. + The result is undefined if $e$ does not exist. This function uses + + \item a combination of generic discrete log algorithms (see \tet{znlog}) + + \item a cubic sieve index calculus algorithm for large fields of degree at + least $5$. + + \item Coppersmith's algorithm for fields of characteristic at most $5$. + + \bprog + ? t = ffgen(ffinit(7,5)); + ? o = fforder(t) + %2 = 5602 \\@com \emph{not} a primitive root. + ? fflog(t^10,t) + %3 = 10 + ? fflog(t^10,t, o) + %4 = 10 + ? g = ffprimroot(t, &o); + ? o \\ order is 16806, bundled with its factorization matrix + %6 = [16806, [2, 1; 3, 1; 2801, 1]] + ? fforder(g, o) + %7 = 16806 + ? fflog(g^10000, g, o) + %8 = 10000 + @eprog + +Function: ffmap +Class: basic +Section: number_theoretical +C-Name: ffmap +Prototype: GG +Help: ffmap(m,x): given a (partial) map m between two finite fields, + return the image of x by m. The function is applied recursively to the + component of vectors, matrices and polynomials. If m is a partial map that + is not defined at x, return [] +Doc: given a (partial) map $m$ between two finite fields, return the image of + $x$ by $m$. The function is applied recursively to the component of vectors, + matrices and polynomials. If $m$ is a partial map that is not defined at $x$, + return $[]$. + \bprog + ? a = ffgen([3,5],'a); + ? b = ffgen([3,10],'b); + ? m = ffembed(a, b); + ? P = x^2+a*x+1; + ? Q = ffmap(m,P); + ? ffmap(m,poldisc(P)) == poldisc(Q) + %6 = 1 + @eprog + +Function: ffmaprel +Class: basic +Section: number_theoretical +C-Name: ffmaprel +Prototype: GG +Help: ffmaprel(m,x): given a (partial) map m between two finite fields, + express x as an algebraic element over the codomain of m in a way which + is compatible with m. + The function is applied recursively to the component of vectors, matrices and + polynomials. +Doc: given a (partial) map $m$ between two finite fields, express $x$ as an + algebraic element over the codomain of $m$ in a way which is compatible + with $m$. + The function is applied recursively to the component of vectors, + matrices and polynomials. + \bprog + ? a = ffgen([3,5],'a); + ? b = ffgen([3,10],'b); + ? m = ffembed(a, b); + ? mi= ffinvmap(m); + ? R = ffmaprel(mi,b) + %5 = Mod(b,b^2+(a+1)*b+(a^2+2*a+2)) + @eprog + In particular, this function can be used to compute the relative minimal + polynomial, norm and trace: + \bprog + ? minpoly(R) + %6 = x^2+(a+1)*x+(a^2+2*a+2) + ? trace(R) + %7 = 2*a+2 + ? norm(R) + %8 = a^2+2*a+2 + @eprog + +Function: ffnbirred +Class: basic +Section: number_theoretical +C-Name: ffnbirred0 +Prototype: GLD0,L, +Help: ffnbirred(q,n,{flag=0}): number of monic irreducible polynomials over F_q, + of degree n (flag=0, default) or at most n (flag=1). +Description: + (int, small, ?0):int ffnbirred($1, $2) + (int, small, 1):int ffsumnbirred($1, $2) + (int, small, ?small):int ffnbirred0($1, $2, $3) +Doc: computes the number of monic irreducible polynomials over $\F_{q}$ + of degree exactly $n$ ($\fl=0$ or omitted) or at most $n$ ($\fl=1$). +Variant: Also available are + \fun{GEN}{ffnbirred}{GEN q, long n} (for $\fl=0$) + and \fun{GEN}{ffsumnbirred}{GEN q, long n} (for $\fl=1$). + +Function: fforder +Class: basic +Section: number_theoretical +C-Name: fforder +Prototype: GDG +Help: fforder(x,{o}): multiplicative order of the finite field element x. + Optional o represents a multiple of the order of the element. +Doc: multiplicative order of the finite field element $x$. If $o$ is + present, it represents a multiple of the order of the element, + see \secref{se:DLfun}; the preferred format for + this parameter is \kbd{[N, factor(N)]}, where \kbd{N} is the cardinality + of the multiplicative group of the underlying finite field. + \bprog + ? t = ffgen(ffinit(nextprime(10^8), 5)); + ? g = ffprimroot(t, &o); \\@com o will be useful! + ? fforder(g^1000000, o) + time = 0 ms. + %5 = 5000001750000245000017150000600250008403 + ? fforder(g^1000000) + time = 16 ms. \\@com noticeably slower, same result of course + %6 = 5000001750000245000017150000600250008403 + @eprog + +Function: ffprimroot +Class: basic +Section: number_theoretical +C-Name: ffprimroot +Prototype: GD& +Help: ffprimroot(x,{&o}): return a primitive root of the multiplicative group + of the definition field of the finite field element x (not necessarily the + same as the field generated by x). If present, o is set to [ord, fa], where + ord is the order of the group, and fa its factorization + (useful in fflog and fforder). +Doc: return a primitive root of the multiplicative + group of the definition field of the finite field element $x$ (not necessarily + the same as the field generated by $x$). If present, $o$ is set to + a vector \kbd{[ord, fa]}, where \kbd{ord} is the order of the group + and \kbd{fa} its factorization \kbd{factor(ord)}. This last parameter is + useful in \tet{fflog} and \tet{fforder}, see \secref{se:DLfun}. + \bprog + ? t = ffgen(ffinit(nextprime(10^7), 5)); + ? g = ffprimroot(t, &o); + ? o[1] + %3 = 100000950003610006859006516052476098 + ? o[2] + %4 = + [2 1] + + [7 2] + + [31 1] + + [41 1] + + [67 1] + + [1523 1] + + [10498781 1] + + [15992881 1] + + [46858913131 1] + + ? fflog(g^1000000, g, o) + time = 1,312 ms. + %5 = 1000000 + @eprog + +Function: fft +Class: basic +Section: polynomials +C-Name: FFT +Prototype: GG +Help: fft(w,P): given w from rootsof1, return the discrete Fourier transform + of P. +Doc: Let $w=[1,z,\ldots,z^{N-1}]$ from some primitive $N$-roots of unity $z$ + where $N$ is a power of $2$, and $P$ be a polynomial $< N$, + return the unnormalized discrete Fourier transform of $P$, + $\{ P(w[i]), 1 \leq i \leq N\}$. Also allow $P$ to be a vector + $[p_{0},\dots,p_{n}]$ representing the polynomial $\sum_{i} p_{i} X^{i}$. + Composing \kbd{fft} and \kbd{fftinv} returns $N$ times the original input + coefficients. + \bprog + ? w = rootsof1(4); fft(w, x^3+x+1) + %1 = [3, 1, -1, 1] + ? fftinv(w, %) + %2 = [4, 4, 0, 4] + ? Polrev(%) / 4 + %3 = x^3 + x + 1 + ? w = powers(znprimroot(5),3); fft(w, x^3+x+1) + %4 = [Mod(3,5),Mod(1,5),Mod(4,5),Mod(1,5)] + ? fftinv(w, %) + %5 = [Mod(4,5),Mod(4,5),Mod(0,5),Mod(4,5)] + @eprog + +Function: fftinv +Class: basic +Section: polynomials +C-Name: FFTinv +Prototype: GG +Help: fftinv(w,P): given w from rootsof1, return the inverse Fourier transform + of P. +Doc: Let $w=[1,z,\ldots,z^{N-1}]$ from some primitive $N$-roots of unity $z$ + where $N$ is a power of $2$, and $P$ be a polynomial $< N$, + return the unnormalized discrete Fourier transform of $P$, + $\{ P(1 / w[i]), 1 \leq i \leq N\}$. Also allow $P$ to be a vector + $[p_{0},\dots,p_{n}]$ representing the polynomial $\sum_{i} p_{i} X^{i}$. + Composing + \kbd{fft} and \kbd{fftinv} returns $N$ times the original input coefficients. + \bprog + ? w = rootsof1(4); fft(w, x^3+x+1) + %1 = [3, 1, -1, 1] + ? fftinv(w, %) + %2 = [4, 4, 0, 4] + ? Polrev(%) / 4 + %3 = x^3 + x + 1 + + ? N = 512; w = rootsof1(N); T = random(1000 * x^(N-1)); + ? U = fft(w, T); + time = 3 ms. + ? V = vector(N, i, subst(T, 'x, w[i])); + time = 65 ms. + ? exponent(V - U) + %7 = -97 + ? round(Polrev(fftinv(w,U) / N)) == T + %8 = 1 + @eprog + +Function: fibonacci +Class: basic +Section: combinatorics +C-Name: fibo +Prototype: L +Help: fibonacci(x): Fibonacci number of index x. +Doc: $x^{\text{th}}$ Fibonacci number. + +Function: fileclose +Class: basic +Section: programming/specific +C-Name: gp_fileclose +Prototype: vL +Help: fileclose(n): close the file descriptor n. +Doc: close the file descriptor $n$, created via \kbd{fileopen} or + \kbd{fileextern}. Finitely many files can be opened at a given time, + closing them recycles file descriptors and avoids running out of them: + \bprog + ? n = 0; while(n++, fileopen("/tmp/test", "w")) + *** at top-level: n=0;while(n++,fileopen("/tmp/test","w")) + *** ^-------------------------- + *** fileopen: error opening requested file: `/tmp/test'. + *** Break loop: type 'break' to go back to GP prompt + break> n + 65533 + @eprog\noindent This is a limitation of the operating system and does not + depend on PARI: if you open too many files in \kbd{gp} without closing them, + the operating system will also prevent unrelated applications from opening + files. Independently, your operating system (e.g. Windows) may prevent other + applications from accessing or deleting your file while it is opened by + \kbd{gp}. Quitting \kbd{gp} implicitly calls this function on all opened + file descriptors. + + On files opened for writing, this function also forces a write of all + buffered data to the file system and completes all pending write operations. + This function is implicitly called for all open file descriptors when + exiting \kbd{gp} but it is cleaner and safer to call it explicitly, for + instance in case of a \kbd{gp} crash or general system failure, which could + cause data loss. + \bprog + ? n = fileopen("./here"); + ? while(l = fileread(n), print(l)); + ? fileclose(n); + + ? n = fileopen("./there", "w"); + ? for (i = 1, 100, filewrite(n, i^2+1)) + ? fileclose(n) + @eprog Until a \kbd{fileclose}, there is no guarantee that the file on disk + contains all the expected data from previous \kbd{filewrite}s. (And even + then the operating system may delay the actual write to hardware.) + + Closing a file twice raises an exception: + \bprog + ? n = fileopen("/tmp/test"); + ? fileclose(n) + ? fileclose(n) + *** at top-level: fileclose(n) + *** ^------------ + *** fileclose: invalid file descriptor 0 + @eprog + +Function: fileextern +Class: basic +Section: programming/specific +C-Name: gp_fileextern +Prototype: ls +Help: fileextern(str): execute shell command str and returns a file + descriptor attached to the command output as if it were read from a file. +Doc: the string \var{str} is the name of an external command, i.e.~one you + would type from your UNIX shell prompt. This command is immediately run and + the function returns a file descriptor attached to the command output as if + it were read from a file. + \bprog + ? n = fileextern("ls -l"); + ? while(l = filereadstr(n), print(l)) + ? fileclose(n) + @eprog\noindent If the \kbd{secure} default is set, this function will raise + en exception. + +Function: fileflush +Class: basic +Section: programming/specific +C-Name: gp_fileflush0 +Prototype: vDG +Help: fileflush({n}): flush the file descriptor n (all descriptors to output + streams if n is omitted). +Doc: flushes the file descriptor $n$, created via \kbd{fileopen} or + \kbd{fileextern}. On files opened for writing, this function forces a write + of all buffered data to the file system and completes all pending write + operations. This function is implicitly called by \kbd{fileclose} but you may + want to call it explicitly at synchronization points, for instance after + writing a large result to file and before printing diagnostics on screen. + (In order to be sure that the file contains the expected content on + inspection.) + + If $n$ is omitted, flush all descriptors to output streams. + + \bprog + ? n = fileopen("./here", "w"); + ? for (i = 1, 10^5, \ + filewrite(n, i^2+1); \ + if (i % 10000 == 0, fileflush(n))) + @eprog Until a \kbd{fileflush} or \kbd{fileclose}, there is no guarantee + that the file contains all the expected data from previous \kbd{filewrite}s. +Variant: But the direct and more specific variant + \fun{void}{gp_fileflush}{long n} is also available. + +Function: fileopen +Class: basic +Section: programming/specific +C-Name: gp_fileopen +Prototype: lsD"r",s, +Help: fileopen(path,mode): open the file pointed to by 'path' and return a + file descriptor which can be used with other file functions. + The mode is "r" (default, read), "w" (write, truncate), "a" (write, append). +Doc: open the file pointed to by 'path' and return a file descriptor which + can be used with other file functions. + + The mode can be + + \item \kbd{"r"} (default): open for reading; allow \kbd{fileread} and + \kbd{filereadstr}. + + \item \kbd{"w"}: open for writing, discarding existing content; allow + \kbd{filewrite}, \kbd{filewrite1}. + + \item \kbd{"a"}: open for writing, appending to existing content; same + operations allowed as \kbd{"w"}. + + Eventually, the file should be closed and the descriptor recycled using + \kbd{fileclose}. + + \bprog + ? n = fileopen("./here"); \\ "r" by default + ? while (l = filereadstr(n), print(l)) \\ print successive lines + ? fileclose(n) \\ done + @eprog\noindent In \emph{read} mode, raise an exception if the file does not + exist or the user does not have read permission. In \emph{write} mode, raise + an exception if the file cannot be written to. Trying to read or write to a + file that was not opend with the right mode raises an exception. + \bprog + ? n = fileopen("./read", "r"); + ? filewrite(n, "test") \\ not open for writing + *** at top-level: filewrite(n,"test") + *** ^------------------- + *** filewrite: invalid file descriptor 0 + @eprog + +Function: fileread +Class: basic +Section: programming/specific +C-Name: gp_fileread +Prototype: L +Help: fileread(n): read a logical line from the file attached to the + descriptor n, opened for reading with fileopen. Return 0 at end of file. +Doc: read a logical line from the file attached to the descriptor $n$, opened + for reading with \kbd{fileopen}. Return 0 at end of file. + + A logical line is a full command as it is prepared by gp's + preprocessor (skipping blanks and comments or assembling multiline commands + between braces) before being fed to the interpreter. The function + \kbd{filereadstr} would read a \emph{raw} line exactly as input, up to the + next carriage return \kbd{\bs n}. + + Compare raw lines + \bprog + ? n = fileopen("examples/bench.gp"); + ? while(l = filereadstr(n), print(l)); + { + u=v=p=q=1; + for (k=1, 2000, + [u,v] = [v,u+v]; + p *= v; q = lcm(q,v); + if (k%50 == 0, + print(k, " ", log(p)/log(q)) + ) + ) + } + @eprog\noindent and logical lines + \bprog + ? n = fileopen("examples/bench.gp"); + ? while(l = fileread(n), print(l)); + u=v=p=q=1;for(k=1,2000,[u,v]=[v,u+v];p*=v;q=lcm(q,v);[...] + @eprog + +Function: filereadstr +Class: basic +Section: programming/specific +C-Name: gp_filereadstr +Prototype: L +Help: filereadstr(n): read a raw line from the file attached to the + descriptor n, opened for reading with fileopen. Discard the terminating + newline. Return 0 at end of file. +Doc: read a raw line from the file attached to the descriptor $n$, opened + for reading with \kbd{fileopen}, discarding the terminating newline. + In other words the line is read exactly as input, up to the + next carriage return \kbd{\bs n}. By comparison, \kbd{fileread} would + read a logical line, as assembled by gp's preprocessor (skipping blanks + and comments for instance). + +Function: filewrite +Class: basic +Section: programming/specific +C-Name: gp_filewrite +Prototype: vLs +Help: filewrite(n,s): write the string s to file attached to descriptor n, + ending with a newline. The file must have been opened with fileopen in + "w" or "a" mode. +Doc: write the string $s$ to the file attached to descriptor $n$, ending with + a newline. The file must have been opened with \kbd{fileopen} in + \kbd{"w"} or \kbd{"a"} mode. There is no guarantee that $s$ is completely + written to disk until \kbd{fileclose$(n)$} is executed, which is automatic + when quitting \kbd{gp}. + + If the newline is not desired, use \kbd{filewrite1}. + + \misctitle{Variant} The high-level function \kbd{write} is expensive when many + consecutive writes are expected because it cannot use buffering. The low-level + interface \kbd{fileopen} / \kbd{filewrite} / \kbd{fileclose} is more efficient: + \bprog + ? f = "/tmp/bigfile"; + ? for (i = 1, 10^5, write(f, i^2+1)) + time = 240 ms. + + ? v = vector(10^5, i, i^2+1); + time = 10 ms. \\ computing the values is fast + ? write("/tmp/bigfile2",v) + time = 12 ms. \\ writing them in one operation is fast + + ? n = fileopen("/tmp/bigfile", "w"); + ? for (i = 1, 10^5, filewrite(n, i^2+1)) + time = 24 ms. \\ low-level write is ten times faster + ? fileclose(n); + @eprog\noindent In the final example, the file needs not be in a consistent + state until the ending \kbd{fileclose} is evaluated, e.g. some lines might be + half-written or not present at all even though the corresponding + \kbd{filewrite} was executed already. Both a single high-level \kbd{write} + and a succession of low-level \kbd{filewrite}s achieve the same efficiency, + but the latter is often more natural. In fact, concatenating naively + the entries to be written is quadratic in the number of entries, hence + much more expensive than the original write operations: + \bprog + ? v = []; for (i = 1, 10^5, v = concat(v,i)) + time = 1min, 41,456 ms. + @eprog + +Function: filewrite1 +Class: basic +Section: programming/specific +C-Name: gp_filewrite1 +Prototype: vLs +Help: filewrite1(n,s): write the string s to file number n without ending with newline. +Doc: write the string $s$ to the file attached to descriptor $n$. + The file must have been opened with \kbd{fileopen} in \kbd{"w"} or \kbd{"a"} + mode. + + If you want to append a newline at the end of $s$, you can use + \kbd{Str(s,"\bs n")} or \kbd{filewrite}. + +Function: floor +Class: basic +Section: conversions +C-Name: gfloor +Prototype: G +Help: floor(x): floor of x = largest integer <= x. +Description: + (small):small:parens $1 + (int):int:copy:parens $1 + (real):int floorr($1) + (mp):int mpfloor($1) + (gen):gen gfloor($1) +Doc: + floor of $x$. When $x$ is in $\R$, the result is the + largest integer smaller than or equal to $x$. Applied to a rational function, + $\kbd{floor}(x)$ returns the Euclidean quotient of the numerator by the + denominator. + +Function: fold +Class: basic +Section: programming/specific +C-Name: fold0 +Prototype: GG +Help: fold(f,A): return f(...f(f(A[1],A[2]),A[3]),...,A[#A]). +Wrapper: (GG) +Description: + (closure,gen):gen genfold(${1 cookie}, ${1 wrapper}, $2) +Doc: Apply the \typ{CLOSURE} \kbd{f} of arity $2$ to the entries of \kbd{A}, + in order to return \kbd{f(\dots f(f(A[1],A[2]),A[3])\dots ,A[\#A])}. + \bprog + ? fold((x,y)->x*y, [1,2,3,4]) + %1 = 24 + ? fold((x,y)->[x,y], [1,2,3,4]) + %2 = [[[1, 2], 3], 4] + ? fold((x,f)->f(x), [2,sqr,sqr,sqr]) + %3 = 256 + ? fold((x,y)->(x+y)/(1-x*y),[1..5]) + %4 = -9/19 + ? bestappr(tan(sum(i=1,5,atan(i)))) + %5 = -9/19 + @eprog +Variant: Also available is + \fun{GEN}{genfold}{void *E, GEN (*fun)(void*,GEN, GEN), GEN A}. + +Function: for +Class: basic +Section: programming/control +C-Name: forpari +Prototype: vV=GGI +Help: for(X=a,b,seq): the sequence is evaluated, X going from a up to b. + If b is set to +oo, the loop will not stop. +Doc: evaluates \var{seq}, where + the formal variable $X$ goes from $a$ to $b$, where $a$ and $b$ must be in + $\R$. Nothing is done if $a>b$. If $b$ is set to \kbd{+oo}, the loop will not + stop; it is expected that the caller will break out of the loop itself at some + point, using \kbd{break} or \kbd{return}. + +Function: forcomposite +Class: basic +Section: programming/control +C-Name: forcomposite +Prototype: vV=GDGI +Help: forcomposite(n=a,{b},seq): the sequence is evaluated, n running over the + composite numbers between a and b. Omitting b runs through composites >= a. +Iterator: + (gen,gen,?gen) (forcomposite, _forcomposite_init, _forcomposite_next) +Doc: evaluates \var{seq}, + where the formal variable $n$ ranges over the composite numbers between the + nonnegative real numbers $a$ to $b$, including $a$ and $b$ if they are + composite. Nothing is done if $a>b$. + \bprog + ? forcomposite(n = 0, 10, print(n)) + 4 + 6 + 8 + 9 + 10 + @eprog\noindent Omitting $b$ means we will run through all composites $\geq a$, + starting an infinite loop; it is expected that the user will break out of + the loop himself at some point, using \kbd{break} or \kbd{return}. + + Note that the value of $n$ cannot be modified within \var{seq}: + \bprog + ? forcomposite(n = 2, 10, n = []) + *** at top-level: forcomposite(n=2,10,n=[]) + *** ^--- + *** index read-only: was changed to []. + @eprog + +Function: fordiv +Class: basic +Section: programming/control +C-Name: fordiv +Prototype: vGVI +Help: fordiv(n,X,seq): the sequence is evaluated, X running over the + divisors of n. +Doc: evaluates \var{seq}, where + the formal variable $X$ ranges through the divisors of $n$ + (see \tet{divisors}, which is used as a subroutine). It is assumed that + \kbd{factor} can handle $n$, without negative exponents. Instead of $n$, + it is possible to input a factorization matrix, i.e. the output of + \kbd{factor(n)}. + + This routine uses \kbd{divisors} as a subroutine, then loops over the + divisors. In particular, if $n$ is an integer, divisors are sorted by + increasing size. + + To avoid storing all divisors, possibly using a lot of memory, the following + (slower) routine loops over the divisors using essentially constant space: + \bprog + FORDIV(N)= + { my(F = factor(N), P = F[,1], E = F[,2]); + + forvec(v = vector(#E, i, [0,E[i]]), X = factorback(P, v)); + } + ? for(i=1, 10^6, FORDIV(i)) + time = 11,180 ms. + ? for(i=1, 10^6, fordiv(i, d, )) + time = 2,667 ms. + @eprog\noindent Of course, the divisors are no longer sorted by inreasing + size. + +Function: fordivfactored +Class: basic +Section: programming/control +C-Name: fordivfactored +Prototype: vGVI +Help: fordivfactored(n,X,seq): the sequence is evaluated, X running over the + [d, factor(d)], d a divisor of n. +Doc: evaluates \var{seq}, where + the formal variable $X$ ranges through $[d, \kbd{factor}(d)]$, + where $d$ is a divisors of $n$ + (see \tet{divisors}, which is used as a subroutine). Note that such a pair + is accepted as argument to all multiplicative functions. + + It is assumed that + \kbd{factor} can handle $n$, without negative exponents. Instead of $n$, + it is possible to input a factorization matrix, i.e. the output of + \kbd{factor(n)}. This routine uses \kbd{divisors}$(,1)$ as a subroutine, + then loops over the divisors. In particular, if $n$ is an integer, divisors + are sorted by increasing size. + + This function is particularly useful when $n$ is hard to factor and one + must evaluate multiplicative function on its divisors: we avoid + refactoring each divisor in turn. It also provides a small speedup + when $n$ is easy to factor; compare + \bprog + ? A = 10^8; B = A + 10^5; + ? for (n = A, B, fordiv(n, d, eulerphi(d))); + time = 2,091 ms. + ? for (n = A, B, fordivfactored(n, d, eulerphi(d))); + time = 1,298 ms. \\ avoid refactoring the divisors + ? forfactored (n = A, B, fordivfactored(n, d, eulerphi(d))); + time = 1,270 ms. \\ also avoid factoring the consecutive n's ! + @eprog + +Function: foreach +Class: basic +Section: programming/control +C-Name: foreachpari +Prototype: vGVI +Help: foreach(V,X,seq): the sequence is evaluated, X running over the + components of V. +Doc: evaluates \var{seq}, where the formal variable $X$ ranges through the + components of $V$ (\typ{VEC}, \typ{COL}, \typ{LIST} or \typ{MAT}). A matrix + argument is interpreted as a vector containing column vectors, as in + \kbd{Vec}$(V)$. + +Function: forell +Class: basic +Section: programming/control +C-Name: forell0 +Prototype: vVLLID0,L, +Help: forell(E,a,b,seq,{flag=0}): execute seq for each elliptic curves E of + conductor between a and b in the elldata database. If flag is nonzero, select + only the first curve in each isogeny class. +Wrapper: (,,,vG,) +Description: + (,small,small,closure,?small):void forell(${4 cookie}, ${4 wrapper}, $2, $3, $5) +Doc: evaluates \var{seq}, where the formal variable $E = [\var{name}, M, G]$ + ranges through all elliptic curves of conductors from $a$ to $b$. In this + notation \var{name} is the curve name in Cremona's elliptic curve database, + $M$ is the minimal model, $G$ is a $\Z$-basis of the free part of the + Mordell-Weil group $E(\Q)$. If $\fl$ is nonzero, select + only the first curve in each isogeny class. + \bprog + ? forell(E, 1, 500, my([name,M,G] = E); \ + if (#G > 1, print(name))) + 389a1 + 433a1 + 446d1 + ? c = 0; forell(E, 1, 500, c++); c \\ number of curves + %2 = 2214 + ? c = 0; forell(E, 1, 500, c++, 1); c \\ number of isogeny classes + %3 = 971 + @eprog\noindent + The \tet{elldata} database must be installed and contain data for the + specified conductors. + + \synt{forell}{void *data, long (*f)(void*,GEN), long a, long b, long flag}. + +Function: forfactored +Class: basic +Section: programming/control +C-Name: forfactored +Prototype: vV=GGI +Help: forfactored(N=a,b,seq): the sequence is evaluated, N is of the form + [n, factor(n)], n going from a up to b. +Doc: evaluates \var{seq}, where + the formal variable $N$ is $[n, \kbd{factor}(n)]$ and $n$ goes from + $a$ to $b$; $a$ and $b$ must be integers. Nothing is done if $a>b$. + + This function is only implemented for $|a|, |b| < 2^{64}$ ($2^{32}$ on a 32-bit + machine). It uses a sieve and runs in time $O(\sqrt{b} + b-a)$. It should + be at least 3 times faster than regular factorization as long as the interval + length $b-a$ is much larger than $\sqrt{b}$ and get relatively faster as + the bounds increase. The function slows down dramatically + if $\kbd{primelimit} < \sqrt{b}$. + + \bprog + ? B = 10^9; + ? for (N = B, B+10^6, factor(N)) + time = 4,538 ms. + ? forfactored (N = B, B+10^6, [n,fan] = N) + time = 1,031 ms. + + ? B = 10^11; + ? for (N = B, B+10^6, factor(N)) + time = 15,575 ms. + ? forfactored (N = B, B+10^6, [n,fan] = N) + time = 2,375 ms. + + ? B = 10^14; + ? for (N = B, B+10^6, factor(N)) + time = 1min, 4,948 ms. + ? forfactored (N = B, B+10^6, [n,fan] = N) + time = 58,601 ms. + @eprog\noindent The last timing is with the default \kbd{primelimit} + (500000) which is much less than $\sqrt{B+10^{6}}$; it goes down + to \kbd{26,750ms} if \kbd{primelimit} gets bigger than that bound. + In any case $\sqrt{B+10^{6}}$ is much larger than the interval length $10^{6}$ + so \kbd{forfactored} gets relatively slower for that reason as well. + + Note that all PARI multiplicative functions accept the \kbd{[n,fan]} + argument natively: + \bprog + ? s = 0; forfactored(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s + time = 6,001 ms. + %1 = 6393738650 + ? s = 0; for(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s + time = 28,398 ms. \\ slower, we must factor N. Twice. + %2 = 6393738650 + @eprog + + The following loops over the fundamental dicriminants less than $X$: + \bprog + ? X = 10^8; + ? forfactored(d=1,X, if (isfundamental(d),)); + time = 34,030 ms. + ? for(d=1,X, if (isfundamental(d),)) + time = 1min, 24,225 ms. + @eprog + +Function: forpart +Class: basic +Section: programming/control +C-Name: forpart0 +Prototype: vV=GIDGDG +Help: forpart(X=k,seq,{a=k},{n=k}): evaluate seq where the Vecsmall X + goes over the partitions of k. Optional parameter n (n=nmax or n=[nmin,nmax]) + restricts the length of the partition. Optional parameter a (a=amax or + a=[amin,amax]) restricts the range of the parts. Zeros are removed unless one + sets amin=0 to get X of fixed length nmax (=k by default). +Iterator: + (gen,small,?gen,?gen) (forpart, _forpart_init, _forpart_next) +Wrapper: (,vG,,) +Description: + (small,closure,?gen,?gen):void forpart(${2 cookie}, ${2 wrapper}, $1, $3, $4) +Doc: evaluate \var{seq} over the partitions $X=[x_{1},\dots x_{n}]$ of the + integer $k$, i.e.~increasing sequences $x_{1}\leq x_{2}\dots \leq x_{n}$ of sum + $x_{1}+\dots + x_{n}=k$. By convention, $0$ admits only the empty partition and + negative numbers have no partitions. A partition is given by a + \typ{VECSMALL}, where parts are sorted in nondecreasing order. The + partitions are listed by increasing size and in lexicographic order when + sizes are equal: + \bprog + ? forpart(X=4, print(X)) + Vecsmall([4]) + Vecsmall([1, 3]) + Vecsmall([2, 2]) + Vecsmall([1, 1, 2]) + Vecsmall([1, 1, 1, 1]) + @eprog\noindent Optional parameters $n$ and $a$ are as follows: + + \item $n=\var{nmax}$ (resp. $n=[\var{nmin},\var{nmax}]$) restricts + partitions to length less than $\var{nmax}$ (resp. length between + $\var{nmin}$ and $nmax$), where the \emph{length} is the number of nonzero + entries. + + \item $a=\var{amax}$ (resp. $a=[\var{amin},\var{amax}]$) restricts the parts + to integers less than $\var{amax}$ (resp. between $\var{amin}$ and + $\var{amax}$). + + By default, parts are positive and we remove zero entries unless $amin\leq0$, + in which case we fix the size $\#X = \var{nmax}$: + \bprog + \\ at most 3 nonzero parts, all <= 4 + ? forpart(v=5,print(Vec(v)), 4, 3) + [1, 4] + [2, 3] + [1, 1, 3] + [1, 2, 2] + + \\ between 2 and 4 parts less than 5, fill with zeros + ? forpart(v=5,print(Vec(v)),[0,5],[2,4]) + [0, 0, 1, 4] + [0, 0, 2, 3] + [0, 1, 1, 3] + [0, 1, 2, 2] + [1, 1, 1, 2] + + \\ no partitions of 1 with 2 to 4 nonzero parts + ? forpart(v=1,print(v),[0,5],[2,4]) + ? + @eprog\noindent + The behavior is unspecified if $X$ is modified inside the loop. + + \synt{forpart}{void *data, long (*call)(void*,GEN), long k, GEN a, GEN n}. + +Function: forperm +Class: basic +Section: programming/control +C-Name: forperm0 +Prototype: vGVI +Help: forperm(a,p,seq): the sequence is evaluated, p going through permutations of a. +Iterator: + (gen,gen) (forperm, _forperm_init, _forperm_next) +Wrapper: (,vG,,) +Doc: evaluates \var{seq}, where the formal variable $p$ goes through some + permutations given by a \typ{VECSMALL}. If $a$ is a positive integer then + $P$ goes through the permutations of $\{1, 2, ..., a\}$ in lexicographic + order and if $a$ is a small vector then $p$ goes through the + (multi)permutations lexicographically larger than or equal to $a$. + \bprog + ? forperm(3, p, print(p)) + Vecsmall([1, 2, 3]) + Vecsmall([1, 3, 2]) + Vecsmall([2, 1, 3]) + Vecsmall([2, 3, 1]) + Vecsmall([3, 1, 2]) + Vecsmall([3, 2, 1]) + @eprog\noindent + + When $a$ is itself a \typ{VECSMALL} or a \typ{VEC} then $p$ iterates through + multipermutations + \bprog + ? forperm([2,1,1,3], p, print(p)) + Vecsmall([2, 1, 1, 3]) + Vecsmall([2, 1, 3, 1]) + Vecsmall([2, 3, 1, 1]) + Vecsmall([3, 1, 1, 2]) + Vecsmall([3, 1, 2, 1]) + Vecsmall([3, 2, 1, 1]) + @eprog\noindent + +Function: forprime +Class: basic +Section: programming/control +C-Name: forprime +Prototype: vV=GDGI +Help: forprime(p=a,{b},seq): the sequence is evaluated, p running over the + primes between a and b. Omitting b runs through primes >= a. +Iterator: + (*notype,small,small) (forprime, _u_forprime_init, _u_forprime_next) + (*notype,gen,gen,gen) (forprime, _forprime_init, _forprime_next_) + (*small,gen,?gen) (forprime, _u_forprime_init, _u_forprime_next) + (*int,gen,?gen) (forprime, _forprime_init, _forprime_next_) + (gen,gen,?gen) (forprime, _forprime_init, _forprime_next_) +Doc: evaluates \var{seq}, + where the formal variable $p$ ranges over the prime numbers between the real + numbers $a$ to $b$, including $a$ and $b$ if they are prime. More precisely, + the value of + $p$ is incremented to \kbd{nextprime($p$ + 1)}, the smallest prime strictly + larger than $p$, at the end of each iteration. Nothing is done if $a>b$. + \bprog + ? forprime(p = 4, 10, print(p)) + 5 + 7 + @eprog\noindent Setting $b$ to \kbd{+oo} means we will run through all primes + $\geq a$, starting an infinite loop; it is expected that the caller will break + out of the loop itself at some point, using \kbd{break} or \kbd{return}. + + Note that the value of $p$ cannot be modified within \var{seq}: + \bprog + ? forprime(p = 2, 10, p = []) + *** at top-level: forprime(p=2,10,p=[]) + *** ^--- + *** prime index read-only: was changed to []. + @eprog + +Function: forprimestep +Class: basic +Section: programming/control +C-Name: forprimestep +Prototype: vV=GDGGI +Help: forprimestep(p=a,b,q,seq): the sequence is evaluated, p running over the + primes less than b in the arithmetic progression a + k*q, k >= 0. + The parameter q can be a positive integer or an intmod (start at the first + prime above a in the progression). +Iterator: + (*notype,small,small,gen) (forprime, _forprimestep_init, _u_forprime_next) + (*notype,gen,gen,gen) (forprime, _forprimestep_init, _forprime_next_) + (*small,gen,?gen,gen) (forprime, _forprimestep_init, _u_forprime_next) + (*int,gen,?gen,gen) (forprime, _forprimestep_init, _forprime_next_) + (gen,gen,?gen,gen) (forprime, _forprimestep_init, _forprime_next_) +Doc: evaluates \var{seq}, where the formal variable $p$ ranges over the prime + numbers in an arithmetic progression in $[a,b]$: $q$ is either an integer + ($p \equiv a \pmod{q}$) or an intmod \kbd{Mod(c,N)} and we restrict + to that congruence class. Nothing is done if $a>b$. + \bprog + ? forprimestep(p = 4, 30, 5, print(p)) + 19 + 29 + ? forprimestep(p = 4, 30, Mod(1,5), print(p)) + 11 + @eprog\noindent Setting $b$ to \kbd{+oo} means we will run through all primes + $\geq a$, starting an infinite loop; it is expected that the caller will break + out of the loop itself at some point, using \kbd{break} or \kbd{return}. + + Note that the value of $p$ cannot be modified within \var{seq}: + \bprog + ? forprimestep(p = 2, 10, 3, p = []) + *** at top-level: forprimestep(p=2,10,3,p=[]) + *** ^--- + *** prime index read-only: was changed to []. + @eprog + +Function: forqfvec +Class: basic +Section: linear_algebra +C-Name: forqfvec0 +Prototype: vVGDGI +Help: forqfvec(v,q,b,expr): q being a square and symmetric integral matrix + representing an positive definite quadratic form, evaluate expr + for all pairs of nonzero vectors (-v, v) such that q(v)<=b. +Wrapper: (,,,vG) +Description: + (,gen,?gen,closure):void forqfvec1(${4 cookie}, ${4 wrapper}, $2, $3) +Doc: $q$ being a square and symmetric integral matrix representing a positive + definite quadratic form, evaluate \kbd{expr} for all pairs of nonzero + vectors $(-v,v)$ such that $q(v)\leq b$. The formal variable $v$ runs + through representatives of all such pairs in turn. + \bprog + ? forqfvec(v, [3,2;2,3], 3, print(v)) + [0, 1]~ + [1, 0]~ + [-1, 1]~ + @eprog +Variant: The following functions are also available: + \fun{void}{forqfvec}{void *E, long (*fun)(void *, GEN, GEN, double), GEN q, GEN b}: + Evaluate \kbd{fun(E,U,v,m)} on all $v$ such that $q(U\*v)b$. + + \bprog + ? forsquarefree(N=-3,9,print(N)) + [-3, [-1, 1; 3, 1]] + [-2, [-1, 1; 2, 1]] + [-1, Mat([-1, 1])] + [1, matrix(0,2)] + [2, Mat([2, 1])] + [3, Mat([3, 1])] + [5, Mat([5, 1])] + [6, [2, 1; 3, 1]] + [7, Mat([7, 1])] + @eprog + + This function is only implemented for $|a|, |b| < 2^{64}$ ($2^{32}$ on a 32-bit + machine). It uses a sieve and runs in time $O(\sqrt{b} + b-a)$. It should + be at least 5 times faster than regular factorization as long as the interval + length $b-a$ is much larger than $\sqrt{b}$ and get relatively faster as + the bounds increase. The function slows down dramatically + if $\kbd{primelimit} < \sqrt{b}$. It is comparable to \kbd{forfactored}, but + about $\zeta(2) = \pi^{2}/6$ times faster due to the relative density + of squarefree integers. + + \bprog + ? B = 10^9; + ? for (N = B, B+10^6, factor(N)) + time = 2,463 ms. + ? forfactored (N = B, B+10^6, [n,fan] = N) + time = 567 ms. + ? forsquarefree (N = B, B+10^6, [n,fan] = N) + time = 343 ms. + + ? B = 10^11; + ? for (N = B, B+10^6, factor(N)) + time = 8,012 ms. + ? forfactored (N = B, B+10^6, [n,fan] = N) + time = 1,293 ms. + ? forsquarefree (N = B, B+10^6, [n,fan] = N) + time = 713 ms. + + ? B = 10^14; + ? for (N = B, B+10^6, factor(N)) + time = 41,283 ms. + ? forsquarefree (N = B, B+10^6, [n,fan] = N) + time = 33,399 ms. + @eprog\noindent The last timing is with the default \kbd{primelimit} + (500000) which is much less than $\sqrt{B+10^{6}}$; it goes down + to \kbd{29,253ms} if \kbd{primelimit} gets bigger than that bound. + In any case $\sqrt{B+10^{6}}$ is much larger than the interval length $10^{6}$ + so \kbd{forsquarefree} gets relatively slower for that reason as well. + + Note that all PARI multiplicative functions accept the \kbd{[n,fan]} + argument natively: + \bprog + ? s = 0; forsquarefree(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s + time = 2,003 ms. + %1 = 6393738650 + ? s = 0; for(N = 1, 10^7, s += moebius(N)*eulerphi(N)); s + time = 18,024 ms. \\ slower, we must factor N. Twice. + %2 = 6393738650 + @eprog + + The following loops over the fundamental dicriminants less than $X$: + \bprog + ? X = 10^8; + ? for(d=1,X, if (isfundamental(d),)) + time = 53,387 ms. + ? forfactored(d=1,X, if (isfundamental(d),)); + time = 13,861 ms. + ? forsquarefree(d=1,X, D = quaddisc(d); if (D <= X, )); + time = 14,341 ms. + @eprog\noindent Note that in the last loop, the fundamental discriminants + $D$ are not evaluated in order (since \kbd{quaddisc(d)} for squarefree $d$ + is either $d$ or $4d$) but the set of numbers we run through is the same. + Not worth the complication since it's slower than testing \kbd{isfundamental}. + A faster, more complicated approach uses two loops. For simplicity, assume + $X$ is divisible by $4$: + \bprog + ? forsquarefree(d=1,X/4, D = quaddisc(d)); + time = 3,642 ms. + ? forsquarefree(d=X/4+1,X, if (d[1] % 4 == 1,)); + time = 7,772 ms. + @eprog\noindent This is the price we pay for a faster evaluation, + + We can run through negative fundamental discriminants in the same way: + \bprog + ? forfactored(d=-X,-1, if (isfundamental(d),)); + @eprog + +Function: forstep +Class: basic +Section: programming/control +C-Name: forstep +Prototype: vV=GGGI +Help: forstep(X=a,b,s,seq): the sequence is evaluated, X going from a to b + in steps of s (can be a positive real number, an intmod for an arithmetic + progression, or finally a vector of steps). If b is set to +oo the loop will + not stop. +Doc: evaluates \var{seq}, where the formal variable $X$ goes from $a$ to $b$ + in increments of $s$. Nothing is done if $s>0$ and $a>b$ or if $s<0$ + and $a 10, break)); + [0, 0] + [-1, 0] + [0, -1] + [0, 1] + [1, 0] + [-2, 0] + [-1, -1] + [-1, 1] + [0, -2] + [0, 2] + [1, -1] + ? zn = znstar(36,1); + ? forvec (chi = zn.cyc, if (chareval(zn,chi,5) == 5/6, print(chi))); + [1, 0] + [1, 1] + ? bnrchar(zn, [5], [5/6]) \\ much more efficient in general + %5 = [[1, 1], [1, 0]] + + @eprog + +Function: frac +Class: basic +Section: conversions +C-Name: gfrac +Prototype: G +Help: frac(x): fractional part of x = x-floor(x). +Doc: + fractional part of $x$. Identical to + $x-\text{floor}(x)$. If $x$ is real, the result is in $[0,1[$. + +Function: fromdigits +Class: basic +Section: conversions +C-Name: fromdigits +Prototype: GDG +Help: fromdigits(x,{b=10}): gives the integer formed by the elements of x seen + as the digits of a number in base b. +Doc: gives the integer formed by the elements of $x$ seen as the digits of a + number in base $b$ ($b = 10$ by default); $b$ must be an integer satisfying + $|b|>1$. This is the reverse of \kbd{digits}: + \bprog + ? digits(1234, 5) + %1 = [1,4,4,1,4] + ? fromdigits([1,4,4,1,4],5) + %2 = 1234 + @eprog\noindent By convention, $0$ has no digits: + \bprog + ? fromdigits([]) + %3 = 0 + @eprog\noindent This function works with $x$ a \typ{VECSMALL}; and + also with $b < 0$ or $x[i]$ not an actual digit in base $b$ (i.e., + $x[i] < 0$ or $x[i] \geq b$): if $x$ has length $n$, we return + $\sum_{i=1}^{n} x[i] b^{n-i}$. + +Function: galoischardet +Class: basic +Section: number_fields +C-Name: galoischardet +Prototype: GGD1,L, +Help: galoischardet(gal,chi,{o=1}): return the determinant character of the + character chi. +Doc: Let $G$ be the group attached to the \kbd{galoisinit} + structure~\var{gal}, and + let $\chi$ be the character of some representation $\rho$ of the group $G$, + where a polynomial variable is to be interpreted as an $o$-th root of 1. + For instance, if \kbd{[T,o] = galoischartable(gal)} the characters + $\chi$ are input as the columns of \kbd{T}. + + Return the degree-$1$ character $\det\rho$ as the list of $\det \rho(g)$, + where $g$ runs through representatives of the conjugacy classes + in \kbd{galoisconjclasses(gal)}, with the same ordering. + \bprog + ? P = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1; + ? polgalois(P) + %2 = [10, 1, 1, "D(5) = 5:2"] + ? K = nfsplitting(P); + ? gal = galoisinit(K); \\ dihedral of order 10 + ? [T,o] = galoischartable(gal); + ? chi = T[,1]; \\ trivial character + ? galoischardet(gal, chi, o) + %7 = [1, 1, 1, 1]~ + ? [galoischardet(gal, T[,i], o) | i <- [1..#T]] \\ all characters + %8 = [[1, 1, 1, 1]~, [1, 1, -1, 1]~, [1, 1, -1, 1]~, [1, 1, -1, 1]~] + @eprog + +Function: galoischarpoly +Class: basic +Section: number_fields +C-Name: galoischarpoly +Prototype: GGD1,L, +Help: galoischarpoly(gal,chi,{o=1}): return the list of characteristic + polynomials of the representation attached to the character chi. +Doc: Let $G$ be the group attached to the \kbd{galoisinit} + structure~\var{gal}, and + let $\chi$ be the character of some representation $\rho$ of the group + $G$, where a polynomial variable is to be interpreted as an $o$-th root of + 1, e.g., if \kbd{[T,o] = galoischartable(gal)} and $\chi$ is a column of + \kbd{T}. + Return the list of characteristic polynomials $\det(1 - \rho(g)T)$, + where $g$ runs through representatives of the conjugacy classes + in \kbd{galoisconjclasses(gal)}, with the same ordering. + \bprog + ? T = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1; + ? polgalois(T) + %2 = [10, 1, 1, "D(5) = 5:2"] + ? K = nfsplitting(T); + ? gal = galoisinit(K); \\ dihedral of order 10 + ? [T,o] = galoischartable(gal); + ? o + %5 = 5 + ? galoischarpoly(gal, T[,1], o) \\ T[,1] is the trivial character + %6 = [-x + 1, -x + 1, -x + 1, -x + 1]~ + ? galoischarpoly(gal, T[,3], o) + %7 = [x^2 - 2*x + 1, + x^2 + (y^3 + y^2 + 1)*x + 1, + -x^2 + 1, + x^2 + (-y^3 - y^2)*x + 1]~ + @eprog + +Function: galoischartable +Class: basic +Section: number_fields +C-Name: galoischartable +Prototype: G +Help: galoischartable(gal): return the character table of the underlying + group of gal. +Doc: Compute the character table of~$G$, where~$G$ is the underlying group of + the \kbd{galoisinit} structure~\var{gal}. The input~\var{gal} is also allowed + to be a \typ{VEC} of permutations that is closed under products. + Let~$N$ be the number of conjugacy classes of~$G$. + Return a \typ{VEC}~$[M,\var{e}]$ where $e \geq 1$ is an integer + and $M$ is a square \typ{MAT} of size~$N$ giving the character table + of~$G$. + + \item Each column corresponds to an irreducible character; the characters + are ordered by increasing dimension and the first column is the trivial + character (hence contains only $1$'s). + + \item Each row corresponds to a conjugacy class; the conjugacy classes are + ordered as specified by \kbd{galoisconjclasses(gal)}, in particular the + first row corresponds to the identity and gives the dimension $\chi(1)$ + of the irreducible representation attached to the successive characters + $\chi$. + + The value $M[i,j]$ of the character $j$ at the conjugacy class $i$ + is represented by a polynomial in \kbd{y} whose variable should be + interpreted as an $e$-th root of unity, i.e. as the lift of + \bprog + Mod(y, polcyclo(e,'y)) + @eprog\noindent (Note that $M$ is the transpose of the usual orientation for + character tables.) + + The integer $e$ divides the exponent of the group $G$ and is chosen as small + as posible; for instance $e = 1$ when the characters are all defined over + $\Q$, as is the case for $S_{n}$. Examples: + \bprog + ? K = nfsplitting(x^4+x+1); + ? gal = galoisinit(K); + ? [M,e] = galoischartable(gal); + ? M~ \\ take the transpose to get the usual orientation + %4 = + [1 1 1 1 1] + + [1 -1 -1 1 1] + + [2 0 0 -1 2] + + [3 -1 1 0 -1] + + [3 1 -1 0 -1] + ? e + %5 = 1 + ? {G = [Vecsmall([1, 2, 3, 4, 5]), Vecsmall([1, 5, 4, 3, 2]), + Vecsmall([2, 1, 5, 4, 3]), Vecsmall([2, 3, 4, 5, 1]), + Vecsmall([3, 2, 1, 5, 4]), Vecsmall([3, 4, 5, 1, 2]), + Vecsmall([4, 3, 2, 1, 5]), Vecsmall([4, 5, 1, 2, 3]), + Vecsmall([5, 1, 2, 3, 4]), Vecsmall([5, 4, 3, 2, 1])];} + \\G = D10 + ? [M,e] = galoischartable(G); + ? M~ + %8 = + [1 1 1 1] + + [1 -1 1 1] + + [2 0 -y^3 - y^2 - 1 y^3 + y^2] + + [2 0 y^3 + y^2 -y^3 - y^2 - 1] + ? e + %9 = 5 + @eprog + +Function: galoisconjclasses +Class: basic +Section: number_fields +C-Name: galoisconjclasses +Prototype: G +Help: galoisconjclasses(gal): gal being output by galoisinit, + return the list of conjugacy classes. +Doc: \var{gal} being output by \kbd{galoisinit}, + return the list of conjugacy classes of the underlying group. + The ordering of the classes is consistent with \kbd{galoischartable} + and the trivial class comes first. + + \bprog + ? G = galoisinit(x^6+108); + ? galoisidentify(G) + %2 = [6, 1] \\ S_3 + ? S = galoisconjclasses(G) + %3 = [[Vecsmall([1,2,3,4,5,6])], + [Vecsmall([3,1,2,6,4,5]),Vecsmall([2,3,1,5,6,4])], + [Vecsmall([6,5,4,3,2,1]),Vecsmall([5,4,6,2,1,3]), + Vecsmall([4,6,5,1,3,2])]] + ? [[permorder(c[1]),#c] | c <- S ] + %4 = [[1,1], [3,2], [2,3]] + @eprog\noindent + This command also accepts subgroups returned by \kbd{galoissubgroups}: + \bprog + ? subs = galoissubgroups(G); H = subs[5]; + ? galoisidentify(H) + %2 = [2, 1] \\ Z/2 + ? S = galoisconjclasses(subgroups_of_G[5]); + ? [[permorder(c[1]),#c] | c <- S ] + %4 = [[1,1], [2,1]] + @eprog\noindent + +Function: galoisexport +Class: basic +Section: number_fields +C-Name: galoisexport +Prototype: GD0,L, +Help: galoisexport(gal,{flag}): gal being a Galois group as output by + galoisinit, output a string representing the underlying permutation group in + GAP notation (default) or Magma notation (flag = 1). +Doc: \var{gal} being be a Galois group as output by \tet{galoisinit}, + export the underlying permutation group as a string suitable + for (no flags or $\fl=0$) GAP or ($\fl=1$) Magma. The following example + compute the index of the underlying abstract group in the GAP library: + \bprog + ? G = galoisinit(x^6+108); + ? s = galoisexport(G) + %2 = "Group((1, 2, 3)(4, 5, 6), (1, 4)(2, 6)(3, 5))" + ? extern("echo \"IdGroup("s");\" | gap -q") + %3 = [6, 1] + ? galoisidentify(G) + %4 = [6, 1] + @eprog\noindent + This command also accepts subgroups returned by \kbd{galoissubgroups}. + + To \emph{import} a GAP permutation into gp (for \tet{galoissubfields} for + instance), the following GAP function may be useful: + \bprog + PermToGP := function(p, n) + return Permuted([1..n],p); + end; + + gap> p:= (1,26)(2,5)(3,17)(4,32)(6,9)(7,11)(8,24)(10,13)(12,15)(14,27) + (16,22)(18,28)(19,20)(21,29)(23,31)(25,30) + gap> PermToGP(p,32); + [ 26, 5, 17, 32, 2, 9, 11, 24, 6, 13, 7, 15, 10, 27, 12, 22, 3, 28, 20, 19, + 29, 16, 31, 8, 30, 1, 14, 18, 21, 25, 23, 4 ] + @eprog + +Function: galoisfixedfield +Class: basic +Section: number_fields +C-Name: galoisfixedfield +Prototype: GGD0,L,Dn +Help: galoisfixedfield(gal,perm,{flag},{v=y}): gal being a Galois group as + output by galoisinit and perm a subgroup, an element of gal.group or a vector + of such elements, return [P,x] such that P is a polynomial defining the fixed + field of gal[1] by the subgroup generated by perm, and x is a root of P in gal + expressed as a polmod in gal.pol. If flag is 1 return only P. If flag is 2 + return [P,x,F] where F is the factorization of gal.pol over the field + defined by P, where the variable v stands for a root of P. +Description: + (gen, gen, ?small, ?var):vec galoisfixedfield($1, $2, $3, $4) +Doc: \var{gal} being be a Galois group as output by \tet{galoisinit} and + \var{perm} an element of $\var{gal}.group$, a vector of such elements + or a subgroup of \var{gal} as returned by galoissubgroups, + computes the fixed field of \var{gal} by the automorphism defined by the + permutations \var{perm} of the roots $\var{gal}.roots$. $P$ is guaranteed to + be squarefree modulo $\var{gal}.p$. + + If no flags or $\fl=0$, output format is the same as for \tet{nfsubfield}, + returning $[P,x]$ such that $P$ is a polynomial defining the fixed field, and + $x$ is a root of $P$ expressed as a polmod in $\var{gal}.pol$. + + If $\fl=1$ return only the polynomial $P$. + + If $\fl=2$ return $[P,x,F]$ where $P$ and $x$ are as above and $F$ is the + factorization of $\var{gal}.pol$ over the field defined by $P$, where + variable $v$ ($y$ by default) stands for a root of $P$. The priority of $v$ + must be less than the priority of the variable of $\var{gal}.pol$ (see + \secref{se:priority}). + In this case, $P$ is also expressed in the variable $v$ for compatibility + with $F$. Example: + + \bprog + ? G = galoisinit(x^4+1); + ? galoisfixedfield(G,G.group[2],2) + %2 = [y^2 - 2, Mod(- x^3 + x, x^4 + 1), [x^2 - y*x + 1, x^2 + y*x + 1]] + @eprog\noindent + computes the factorization $x^{4}+1=(x^{2}-\sqrt{2}x+1)(x^{2}+\sqrt{2}x+1)$ + +Function: galoisgetgroup +Class: basic +Section: number_fields +C-Name: galoisgetgroup +Prototype: LD0,L, +Help: galoisgetgroup(a,{b}): query the galpol package for a group of order a + with index b in the GAP4 Small Group library. If b is omitted, return the + number of isomorphism classes of groups of order a. +Description: + (small):int galoisnbpol($1) + (small,):int galoisnbpol($1) + (small,small):vec galoisgetgroup($1, $2) +Doc: Query the \kbd{galpol} package for a group of order $a$ with index $b$ + in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina Eick and + Eamonn O'Brien. + + The current version of \kbd{galpol} supports groups of order $a\leq 143$. + If $b$ is omitted, return the number of isomorphism classes of + groups of order $a$. +Variant: Also available is \fun{GEN}{galoisnbpol}{long a} when $b$ + is omitted. + +Function: galoisgetname +Class: basic +Section: number_fields +C-Name: galoisgetname +Prototype: LL +Help: galoisgetname(a,b): query the galpol package for a string describing the + group of order a with index b in the GAP4 Small Group library. +Doc: Query the \kbd{galpol} package for a string describing the group of order + $a$ with index $b$ in the GAP4 Small Group library, by Hans Ulrich Besche, + Bettina Eick and Eamonn O'Brien. + The strings were generated using the GAP4 function \kbd{StructureDescription}. + The command below outputs the names of all abstract groups of order 12: + \bprog + ? o = 12; N = galoisgetgroup(o); \\ # of abstract groups of order 12 + ? for(i=1, N, print(i, ". ", galoisgetname(o,i))) + 1. C3 : C4 + 2. C12 + 3. A4 + 4. D12 + 5. C6 x C2 + @eprog\noindent + The current version of \kbd{galpol} supports groups of order $a\leq 143$. + For $a \geq 16$, it is possible for different groups to have the same name: + \bprog + ? o = 20; N = galoisgetgroup(o); + ? for(i=1, N, print(i, ". ", galoisgetname(o,i))) + 1. C5 : C4 + 2. C20 + 3. C5 : C4 + 4. D20 + 5. C10 x C2 + @eprog + +Function: galoisgetpol +Class: basic +Section: number_fields +C-Name: galoisgetpol +Prototype: LD0,L,D1,L, +Help: galoisgetpol(a,{b},{s}): query the galpol package for a polynomial with + Galois group isomorphic to GAP4(a,b), totally real if s=1 (default) and + totally complex if s=2. The output is a vector [pol, den] where pol is the + polynomial and den is the common denominator of the conjugates expressed + as a polynomial in a root of pol. If b and s are omitted, return the number of + isomorphism classes of groups of order a. +Description: + (small):int galoisnbpol($1) + (small,):int galoisnbpol($1) + (small,,):int galoisnbpol($1) + (small,small,small):vec galoisgetpol($1, $2 ,$3) +Doc: Query the \kbd{galpol} package for a polynomial with Galois group + isomorphic to + GAP4(a,b), totally real if $s=1$ (default) and totally complex if $s=2$. + The current version of \kbd{galpol} supports groups of order $a\leq 143$. + The output is a vector [\kbd{pol}, \kbd{den}] where + + \item \kbd{pol} is the polynomial of degree $a$ + + \item \kbd{den} is the denominator of \kbd{nfgaloisconj(pol)}. + Pass it as an optional argument to \tet{galoisinit} or \tet{nfgaloisconj} to + speed them up: + \bprog + ? [pol,den] = galoisgetpol(64,4,1); + ? G = galoisinit(pol); + time = 352ms + ? galoisinit(pol, den); \\ passing 'den' speeds up the computation + time = 264ms + ? % == %` + %4 = 1 \\ same answer + @eprog + If $b$ and $s$ are omitted, return the number of isomorphism classes of + groups of order $a$. +Variant: Also available is \fun{GEN}{galoisnbpol}{long a} when $b$ and $s$ + are omitted. + +Function: galoisidentify +Class: basic +Section: number_fields +C-Name: galoisidentify +Prototype: G +Help: galoisidentify(gal): gal being a Galois group as output by galoisinit, + output the isomorphism class of the underlying abstract group as a + two-components vector [o,i], where o is the group order, and i is the group + index in the GAP4 small group library. +Doc: \var{gal} being be a Galois group as output by \tet{galoisinit}, + output the isomorphism class of the underlying abstract group as a + two-components vector $[o,i]$, where $o$ is the group order, and $i$ is the + group index in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina + Eick and Eamonn O'Brien. + + This command also accepts subgroups returned by \kbd{galoissubgroups}. + + The current implementation is limited to degree less or equal to $127$. + Some larger ``easy'' orders are also supported. + + The output is similar to the output of the function \kbd{IdGroup} in GAP4. + Note that GAP4 \kbd{IdGroup} handles all groups of order less than $2000$ + except $1024$, so you can use \tet{galoisexport} and GAP4 to identify large + Galois groups. + +Function: galoisinit +Class: basic +Section: number_fields +C-Name: galoisinit +Prototype: GDG +Help: galoisinit(pol,{den}): pol being a polynomial or a number field as + output by nfinit defining a Galois extension of Q, compute the Galois group + and all necessary information for computing fixed fields. den is optional + and has the same meaning as in nfgaloisconj(,4)(see manual). +Description: + (gen, ?int):gal galoisinit($1, $2) +Doc: computes the Galois group + and all necessary information for computing the fixed fields of the + Galois extension $K/\Q$ where $K$ is the number field defined by + $\var{pol}$ (monic irreducible polynomial in $\Z[X]$ or + a number field as output by \tet{nfinit}). The extension $K/\Q$ must be + Galois with Galois group ``weakly'' super-solvable, see below; + returns 0 otherwise. Hence this permits to quickly check whether a polynomial + of order strictly less than $48$ is Galois or not. + + The algorithm used is an improved version of the paper + ``An efficient algorithm for the computation of Galois automorphisms'', + Bill Allombert, Math.~Comp, vol.~73, 245, 2001, pp.~359--375. + + A group $G$ is said to be ``weakly'' super-solvable if there exists a + normal series + + $\{1\} = H_{0} \triangleleft H_{1} \triangleleft \cdots \triangleleft H_{n-1} + \triangleleft H_{n}$ + + such that each $H_{i}$ is normal in $G$ and for $i 0.$$ + Error if $s$ is a nonpositive integer, where $\Gamma$ has a (simple) pole. + \bprog + ? gamma(5) \\ @com $\Gamma(n) = (n-1)!$ for a positive integer $n$ + %1 = 24.000000000000000000000000000000000000 + ? gamma(0) + *** at top-level: gamma(0) + *** ^-------- + *** gamma: domain error in gamma: argument = nonpositive integer + + ? gamma(x + O(x^3)) + %2 = x^-1 - 0.57721566490153286060651209008240243104 + O(x) + @eprog + + For $s$ a \typ{PADIC}, evaluates the Morita gamma function at $s$, that + is the unique continuous $p$-adic function on the $p$-adic integers + extending $\Gamma_{p}(k)=(-1)^{k} \prod_{j0$. + + \bprog + ? bnf = bnfinit(x^2-5,1); + ? gc = gcharinit(bnf,[(13*19)^2,[1,1]]); + ? gc.cyc + % = [8892, 6, 2, 0, 0.E-57] + ? chi = [0,0,1,1]~; + ? gcharconductor(gc,chi) + % = [[61009, 7267; 0, 169], [1, 0]] + ? gcharconductor(gc,13*chi) + % = [[4693, 559; 0, 13], [1, 0]] + ? gcharconductor(gc,13*19*chi) + % = [[247, 65; 0, 13], [1, 0]] + ? gcharconductor(gc,13*19*168*chi) + % = [[19, 5; 0, 1], [0, 0]] + @eprog + +Function: gcharduallog +Class: basic +Section: number_fields +C-Name: gcharduallog +Prototype: GG +Help: gcharduallog(gc,chi): returns logarithm vector of character chi + in R^n. + We have gchareval(gc,chi,x,0) = gcharduallog(gc,chi)*gcharlog(gc,x) in R/Z. +Doc: Returns internal logarithm vector of character \kbd{chi} + as a \typ{VEC} in $\R^{n}$, so that for all \var{x}, + \kbd{gchareval}(\var{gc},\var{chi},\var{x},$0$) is equal to + \kbd{gcharduallog}(\var{gc},\var{chi}) * \kbd{gcharlog}(\var{gc},\var{x}) in + $\R/ \Z$. + + The components are organized as follows: + + \item the first \kbd{ns} components are in~$\R$ and describe the character on + the class group generators: $\theta$ encodes~$\goth{p}\mapsto + \exp(2i\pi\theta)$, + + \item the next \kbd{nc} components are in~$\R$ and describe the \kbd{idealstar} + group character via its image on generators: $\theta$ encodes the + image~$\exp(2i\pi\theta)$, + + \item the next $r_{1}+r_{2}$ components are in $\R$ and correspond to characters + of $\R$ for each infinite place: $\varphi$ encodes~$x\mapsto |x|^{i\varphi}$ in + the real case and~$z\mapsto |z|^{2i\varphi}$ in the complex case, + + \item the last $r_{2}$ components are in $\Z$ and correspond to characters of + $\R/\Z$ for each complex place: $k$ encodes~$z\mapsto (z/|z|)^{k}$. + + \item the last component~$s$ is in~$\C$ and corresponds to a + power~$\|\cdot\|^{s}$ of the ad\'elic norm. + + See also \kbd{gcharlog}. + + \bprog + ? bnf = bnfinit(x^3+4*x-1,1); + ? gc = gcharinit(bnf,[1,[1]]); + ? gc.cyc + % = [2, 0, 0, 0.E-57] + ? chi = [0,1,0]~; + ? f = gcharduallog(gc,chi) + % = [0.153497221319231, 1/2, 0.776369647248353, -0.388184823624176, 1, 0] + ? pr = idealprimedec(bnf,2)[1]; + ? v = gcharlog(gc,pr); + ? exp(2*I*Pi*f*v) + % = -0.569867696226731232993110144 - 0.821736459454756074068598760*I + ? gchareval(gc,chi,pr) + % = -0.569867696226731232993110144 - 0.821736459454756074068598760*I + @eprog + +Function: gchareval +Class: basic +Section: number_fields +C-Name: gchareval +Prototype: GGGD1,L, +Help: gchareval(gc,chi,x,{flag=1}): computes the evaluation chi(x) in C* if + flag=1 and in C/Z if flag=0. +Doc: \var{gc} being the structure returned by \kbd{gcharinit}, \var{chi} a + character in \var{gc}, and \var{x} an ideal of the base field, returns the + value~$\chi(x)$. If~$\fl=1$ (default), returns a value in~$\C^{\times}$; + if~$\fl=0$, returns a value in~$\C/\Z$, normalized so that the real part is + between~$-1/2$ and~$1/2$. + + \bprog + ? bnf = bnfinit(x^2-5); + ? gc = gcharinit(bnf,1); + ? chi = [1]~; + ? pr = idealprimedec(bnf,11)[1]; + ? a = gchareval(gc,chi,pr) + % = -0.3804107379142448929315340886 - 0.9248176417432464199580504588*I + ? b = gchareval(gc,chi,pr,0) + % = -0.3121086861831031476247589216 + ? a == exp(2*Pi*I*b) + %7 = 1 + @eprog + +Function: gcharidentify +Class: basic +Section: number_fields +C-Name: gchar_identify +Prototype: GGGp +Help: gcharidentify(gc,Lv,Lchiv): returns a Grossencharacter chi belonging to gc + that approximately satisfies the constraints that chi_v is Lchiv[i] at the + place v=Lv[i]. +Doc: \var{gc} being a Grossencharacter group as output by \kbd{gcharinit}, $Lv$ + being \typ{VEC} of places~$v$ encoded by a \typ{INT} (infinite place) or a prime + ideal structure representing a prime not dividing the modulus of~$gc$ (finite + place), and $Lchiv$ being a \typ{VEC} of local characters~$\chi_{v}$ encoded + by~$[k,\varphi]$ with~$k$ a \typ{INT} and $\varphi$ a \typ{REAL} or + \typ{COMPLEX} representing~$x\mapsto \text{sign}(x)^{k}|x|^{i\varphi}$ (real + place) or~$z\mapsto (z/|z|)^{k}|z|^{2i\varphi}$(complex place) or by a \typ{REAL} + or \typ{COMPLEX}~$\theta$ representing~$\goth{p} \mapsto \exp(2i\pi \theta)$ + (finite place), returns a Grossencharacter~$\psi$ belonging to~$g$ such + that~$\psi_{v} \approx \chi_{v}$ for all~$v$. + At finite places, in place of a scalar one can provide a \typ{VEC} whose + last component is $\theta$, as output by \kbd{gcharlocal}. + To ensure proper identification, it is recommended to provide all infinite + places together with a set of primes that generate the ray class group of + modulus \var{gc}\kbd{.mod}. + + \bprog + ? bnf = bnfinit(x^2-5,1); + ? gc = gcharinit(bnf,1); + ? chi = gcharidentify(gc,[2],[[0,13.]]); + ? gcharlocal(gc,chi,2) + % = [0, 13.057005210545987626926134713745179631] + ? pr = idealprimedec(bnf,11)[1]; + ? chi = gcharidentify(gc,[pr],[0.3]); + ? gchareval(gc,chi,pr,0) + % = 0.30000006229129706787363344444425752636 + @eprog + + If you know only few digits, it may be a good idea to reduce the current + precision to obtain a meaningful result. + + \bprog + ? bnf = bnfinit(x^2-5,1); + ? gc = gcharinit(bnf,1); + ? pr = idealprimedec(bnf,11)[1]; + ? chi = gcharidentify(gc,[pr],[0.184760]) + % = [-420226]~ \\ @com unlikely to be meaningful + ? gchareval(gc,chi,pr,0) + % = 0.18475998070331376194260927294721168954 + ? \p 10 + realprecision = 19 significant digits (10 digits displayed) + ? chi = gcharidentify(gc,[pr],[0.184760]) + % = [-7]~ \\ @com probably what we were looking for + ? gchareval(gc,chi,pr,0) + % = 0.1847608033 + ? \p 38 + realprecision = 38 significant digits + ? gchareval(gc,chi,pr,0) + % = 0.18476080328172203337331245154966763237 + @eprog + + The output may be a quasi-character. + + \bprog + ? bnf = bnfinit(x^2-2,1); + ? gc = gcharinit(bnf,1); gc.cyc + % = [0, 0.E-57] + ? gcharidentify(gc,[1,2],[[0,3.5+1/3*I],[0,-3.5+1/3*I]]) + % = [-1, 1/3]~ + @eprog + +Function: gcharinit +Class: basic +Section: number_fields +C-Name: gcharinit +Prototype: GGp +Help: gcharinit(bnf,f): given a bnf as output by bnfinit and a modulus f, initializes data + related to the group of Grossencharacters of conductor dividing this modulus. +Doc: $\var{bnf}$ being a number field output by \kbd{bnfinit} (including + fundamental units), $f$ a modulus, initializes a structure (\kbd{gc}) + describing the group of Hecke Grossencharacters of modulus $f$. + (As in \tet{idealstar}, the finite part of the conductor may be given + by a factorization into prime ideals, as produced by \tet{idealfactor}.) + + The following member functions are available + on the result: \kbd{.bnf} is the underlying \var{bnf}, + \kbd{.mod} the modulus, \kbd{.cyc} its elementary divisors. + + The internal representation uses a logarithm map on ideals + ${\cal L}: I \to \R^{n}$, + so that a Hecke Grossencharacter $\chi$ can be described by a $n$ + components vector $v$ via + $\chi: a\in I \mapsto \exp(2i\pi v\cdot{{\cal L}(a)})$. + + See \kbd{gcharlog} for more details on the map ${\cal L}$. + + \bprog + ? bnf = bnfinit(polcyclo(5),1); \\ @com initializes number field $\Q(\zeta_5)$ + ? pr = idealprimedec(bnf,5)[1]; \\ @com prime $\goth{p}=(1-\zeta_5)$ above 5 + ? gc = gcharinit(bnf,idealpow(bnf,pr,2)); \\ @com characters of modulus dividing $\goth{p}^{2}$ + ? gc.cyc \\ @com structure as an abelian group + % = [0,0,0,0.E-57] + ? chi = [1,1,-1,0]~; \\ @com a character + ? gcharconductor(gc,chi)[1] + % = + [5 4 1 4] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + @eprog + + Currently, \kbd{gc} is a row vector with 11 components: + + $\var{gc}[1]$ is a matrix whose rows describe a system of generators + of the characters as vectors of $\R^{n}$, under the above description. + + $\var{gc}[2]$ contains the underlying number field \var{bnf} + (\kbd{\var{gc}.bnf}). + + $\var{gc}[3]$ contains the underlying number field \var{nf} + (\kbd{\var{gc}.nf}), possibly stored at higher precision than \var{bnf}. + + $\var{gc}[4]$ contains data for computing in $(\Z_{K}/f)^{\times}$. + + $\var{gc}[5]$ is a vector $S$ of prime ideals which generate the class group. + + $\var{gc}[6]$ contains data to compute discrete logarithms with respect to $S$ + in the class group. + + $\var{gc}[7]$ is a vector \kbd{[Sunits,m]}, where \kbd{Sunits} describes + the $S$-units of $\var{bnf}$ and $m$ is a relation matrix for internal usage. + + $\var{gc}[8]$ is + \kbd{[Vecsmall([evalprec,prec,nfprec]), Vecsmall([ntors,nfree,nalg])]} + caching precisions and various dimensions. + + $\var{gc}[9]$ is a vector describing $\var{gc}$ as a $\Z$-module + via its SNF invariants (\kbd{\var{gc}.cyc}), the last component + representing the norm character. + + $\var{gc}[10]$ is a vector \kbd{[R,U,Ui]} allowing to convert characters + from SNF basis to internal combination of generators. + + Specifically, a character \kbd{chi} in SNF basis has coordinates + \kbd{chi*Ui} in internal basis (the rows of $\var{gc}[1]$). + + $\var{gc}[11]=m$ is the matrix of ${\cal L}(v)$ for all $S$-units $v$. + + $\var{gc}[12]=u$ is an integral base change matrix such that $\var{gc}[1]$ + corresponds to $(mu)^{-1}$. + +Function: gcharisalgebraic +Class: basic +Section: number_fields +C-Name: gcharisalgebraic +Prototype: iGGD& +Help: gcharisalgebraic(gc,chi,{&type}): returns 1 if chi is an algebraic (type A0) + character. If type is present, it is set to the infinity type [p,q] of chi. +Doc: \var{gc} being the structure returned by \kbd{gcharinit} and \var{chi} + a character on \var{gc}, returns 1 if and only if \var{chi} is an algebraic + (Weil type A0) character, so that its infinity type at every complex + embedding~$\tau$ can be written + $$ z \mapsto z^{-p_{\tau}}\bar{z}^{-q_{\tau}} $$ + for some pair of integers $(p_{\tau},q_{\tau})$. + + If \var{type} is given, it is set to the \typ{VEC} of exponents + $[p_{\tau},q_{\tau}]$. + + \bprog + ? bnf = bnfinit(x^4+1,1); + ? gc = gcharinit(bnf,1); + ? gc.cyc + % = [0, 0, 0, 0.E-57] + ? chi1 = [0,0,1]~; + ? gcharisalgebraic(gc,chi1) + % = 0 + ? gcharlocal(gc,chi1,1) + % = [-3, -0.89110698909568455588720672648627467040] + ? chi2 = [1,0,0,-3]~; + ? gcharisalgebraic(gc,chi2,&typ) + % = 1 + ? typ + % = [[6, 0], [2, 4]] + ? gcharlocal(gc,chi2,1) + % = [-6, 3*I] + @eprog + +Function: gcharlocal +Class: basic +Section: number_fields +C-Name: gcharlocal +Prototype: GGGpD& +Help: gcharlocal(gc,chi,v,{&BID}): if v is a place, return the local character + chi_v. If v is a prime dividing the modulus and the optional argument 'BID' + is present, set BID to the corresponding idealstar structure. +Doc: \kbd{gc} being a gchar structure initialised by \kbd{gcharinit}, returns + the local component $\chi_{v}$, where $v$ is either an integer between~$1$ + and~$r_{1}+r_{2}$ encoding an infinite place, or a prime ideal structure + encoding a finite place. + + \item if~$v$ is a real place, $\chi_{v}(x) = {\rm sign}(x)^{k} + |x|^{i\varphi}$ is encoded as~$[k,\varphi]$; + + \item if~$v$ is a complex place, $\chi_{v}(z) = (z/|z|)^{k} |z|^{2i\varphi}$ is + encoded as~$[k,\varphi]$; + + \item if~$v = \goth{p}$ is a finite place not dividing~\var{gc}\kbd{.mod}, + $\chi_{v}(\pi_{v}) = \exp(2i\pi \theta)$ is encoded as~$[\theta]$; + + \item if~$v = \goth{p}$ is a finite place dividing~\var{gc}\kbd{.mod}, + we can define a \var{bid} structure attached to the multiplicative group + $G = (\Z_{K}/\goth{p}^{k})^{*}$, where $\goth{p}^{k}$ divides exactly + \var{gc}\kbd{.mod} (see \kbd{idealstar}). + Then~$\chi_{v}$ is encoded as~$[c_{1},\dots,c_{n},\theta]$ + where~$[c_{1},\dots,c_{n}]$ defines a character on $G$ + (see \kbd{gchareval}) and~$\chi_{v}(\pi_{v}) = \exp(2i\pi\theta)$. + This \var{bid} structure only depends on \kbd{gc} and $v$ + (and not on the character $\chi$); + it can be recovered through the optional argument \var{BID}. + \bprog + ? bnf = bnfinit(x^3-x-1); + ? gc = gcharinit(bnf,1); + ? gc.cyc + % = [0, 0, 0.E-57] + ? chi = [0,1,1/3]~; + ? pr = idealprimedec(bnf,5)[1]; + ? gcharlocal(gc,chi,1) + % = [0, -4.8839310048284836274074581373242545693 - 1/3*I] + ? gcharlocal(gc,chi,2) + % = [6, 2.4419655024142418137037290686621272847 - 1/3*I] + ? gcharlocal(gc,chi,pr) + % = [0.115465135184293124024408915 + 0.0853833331211293579127218326*I] + ? bnf = bnfinit(x^2+1,1); + ? pr3 = idealprimedec(bnf,3)[1]; + ? pr5 = idealprimedec(bnf,5)[1]; + ? gc = gcharinit(bnf,[pr3,2;pr5,3]); + ? gc.cyc + % = [600, 3, 0, 0.E-57] + ? chi = [1,1,1]~; + ? gcharlocal(gc,chi,pr3,&bid) + % = [1, 1, -21/50] + ? bid.cyc + % = [24, 3] + ? gcharlocal(gc,chi,pr5,&bid) + % = [98, -0.30120819117478336291229946188762973702] + ? bid.cyc + % = [100] + @eprog + +Function: gcharlog +Class: basic +Section: number_fields +C-Name: gcharlog +Prototype: GGp +Help: gcharlog(gc,x): returns the internal representation (logarithm) of the + ideal x suitable for computations in gc, as a column vector. +Doc: Returns the internal (logarithmic) representation of the ideal $x$ suitable + for computations in $gc$, as a \typ{COL} in $\R^{n}$. + + Its $n = \kbd{ns+nc}+(r_{1}+r_{2})+r_{2}+1$ components correspond to a + logarithm map on the group of fractional ideals~${\cal L}: I \to \R^{n}$, see + \kbd{gcharinit}. + + More precisely, let $x = (\alpha) \prod \goth{p}_{i}^{a_{i}}$ a + principalization of $x$ on a set $S$ of primes generating + the class group (see \kbd{bnfisprincipal}), + then the logarithm of $x$ is the \typ{COL} + $$ + {\cal L}(x) = \left[ (a_{i}), \log_{f}(\alpha), + \dfrac{\log|x/\alpha|_{\tau}}{2\pi}, + \dfrac{\arg(x/\alpha)_{\tau}}{2\pi}, + \dfrac{\log N(x)}{2\pi}\cdot i \right] + $$ + where + + \item the exponent vector $(a_{i})$ has \kbd{ns} components, where + $\kbd{ns}=\#S$ is the number of prime ideals used to generate the class group, + + \item $\log_{f}(\alpha)$ is a discrete logarithm of + $\alpha$ in the \kbd{idealstar} group $(\Z_{K}/f)^{\times}$, + with \kbd{nc} components, + + \item $\log|x/\alpha|_{\tau}$ has $r_{1}+r_{2}$ components, one for each + real embedding and pair of complex embeddings $\tau\colon K\to\C$ + (and $|z|_{\tau}=|z|^{2}$ for complex $\tau$). + + \item $\arg{(x/\alpha)_{\tau}}$ has $r_{2}$ components, one for each + pair of complex embeddings $\tau\colon K\to\C$. + + \item $N(x)$ is the norm of the ideal~$x$. + + \bprog + ? bnf = bnfinit(x^3-x^2+5*x+1,1); + ? gc = gcharinit(bnf,3); + ? gc.cyc + % = [3, 0, 0, 0.E-57] + ? chi = [1,1,0,-1]~; + ? f = gcharduallog(gc,chi); + ? pr = idealprimedec(bnf,5)[1]; + ? v = gcharlog(gc,pr) + % = [2, -5, -1, 0.0188115475004995312411, -0.0188115475004995312411, + -0.840176314833856764413, 0.256149999363388073738*I]~ + ? exp(2*I*Pi*f*v) + % = -4.5285995080704456583673312 + 2.1193835177957097598574507*I + ? gchareval(gc,chi,pr) + % = -4.5285995080704456583673312 + 2.1193835177957097598574507*I + @eprog + +Function: gcharnewprec +Class: basic +Section: number_fields +C-Name: gcharnewprec +Prototype: Gp +Help: gcharnewprec(gc): given a Grossencharacter group \kbd{gc}, recomputes + its invariants to ensure accurate results to current precision. +Doc: $\var{gc}$ being a Grossencharacter group output by \kbd{gcharinit}, + recomputes its archimedean components ensuring accurate computations to + current precision. + + It is advisable to increase the precision before computing several + values at large ideals. + +Function: genus2igusa +Class: basic +Section: elliptic_curves +C-Name: genus2igusa +Prototype: GD0,L, +Help: genus2igusa(PQ,{k}): let PQ be a polynomial P, resp. a vector [P,Q] of + polynomials defined over a field F of characteristic != 2. Returns the Igusa + invariants of the hyperelliptic curve C/F of genus 2 defined by y^2 = P, + resp. y^2 + Q*y = P. +Doc: Let $PQ$ be a polynomial $P$, resp. a vector $[P,Q]$ of polynomials + defined over a field $F$ of characteristic $\neq 2$. + Returns the Igusa invariants $[J_{2},J_{4},J_{6},J_{8},J_{10}]$ of the + hyperelliptic curve $C/F$, defined by the equation $y^{2} = P(x)$, + resp. $y^{2} + Q(x)*y = P(x)$. If $k$ is given, only return the invariant + of degree $k$ ($k$ must be even between $2$ and $10$). + + \bprog + ? genus2igusa(x^5+3*x^2-4) + %1 = [0, 9600, 20736, -23040000, 177926144] + ? genus2igusa([x^6+x^5-x^4+3*x^3+x^2-2*x+1,x^3-x^2+x-1]) + %2 = [-788, 1958, 341220, -68178781, -662731520] + ? genus2igusa([x^6+x^5-x^4+3*x^3+x^2-2*x+1,x^3-x^2+x-1],4) + %3 = 1958 + ? genus2igusa(x^5+3*Mod(a,a^2-3)*x^2-4) \\ @com{over $\Q(\sqrt{3})$} + %4 = [Mod(0, a^2 - 3), Mod(9600*a, a^2 - 3), Mod(186624, a^2 - 3), + Mod(-69120000, a^2 - 3), Mod(-241864704*a + 204800000, a^2 - 3)] + ? a = ffgen(3^4,'a); \\ @com{over $\F_{3^4} = \F_3[a]$} + ? genus2igusa(x^6+a*x^5-a*x^4+2*x^3+a*x+a+1) + %6 = [2*a^2, a^3 + a^2 + a + 1, a^2 + a + 2, 2*a^3 + 2*a^2 + a + 1, + 2*a^2 + 2] + ? a = ffgen(2^4,'a); \\ @com{$\F_{2^4} = \F_2[a]$} + ? genus2igusa(x^6+a*x^5+a*x^4+a*x+a+1) \\ doesn't work in characteristic 2 + *** at top-level: genus2igusa(x^6+a*x^5+a*x^4+a*x+a+1) + *** ^------------------------------------ + *** genus2igusa: impossible inverse in FF_mul2n: 2. + @eprog + +Function: genus2red +Class: basic +Section: elliptic_curves +C-Name: genus2red +Prototype: GDG +Help: genus2red(PQ,{p}): let PQ be a polynomial P, resp. a vector [P,Q] of + polynomials, with rational coefficients. Determines the reduction at p > 2 + of the (proper, smooth) hyperelliptic curve C/Q of genus 2 defined by + y^2 = P, resp. y^2 + Q*y = P. More precisely, determines the special fiber X_p + of the minimal regular model X of C over Z. +Doc: Let $PQ$ be a polynomial $P$, resp. a vector $[P,Q]$ of polynomials, with + rational coefficients. + Determines the reduction at $p > 2$ of the (proper, smooth) genus~2 + curve $C/\Q$, defined by the hyperelliptic equation $y^{2} = P(x)$, resp. + $y^{2} + Q(x)*y = P(x)$. + (The special fiber $X_{p}$ of the minimal regular model $X$ of $C$ over $\Z$.) + + If $p$ is omitted, determines the reduction type for all (odd) prime + divisors of the discriminant. + + \noindent This function was rewritten from an implementation of Liu's + algorithm by Cohen and Liu (1994), \kbd{genus2reduction-0.3}, see + \url{https://www.math.u-bordeaux.fr/~liu/G2R/}. + + \misctitle{CAVEAT} The function interface may change: for the + time being, it returns $[N,\var{FaN}, [P_{m}, Q_{m}], V]$ + where $N$ is either the local conductor at $p$ or the + global conductor, \var{FaN} is its factorization, $y^{2} +Q_{m}\*y= P_{m}$ + defines a + minimal model over $\Z$ and $V$ describes the reduction type at the + various considered~$p$. Unfortunately, the program is not complete for + $p = 2$, and we may return the odd part of the conductor only: this is the + case if the factorization includes the (impossible) term $2^{-1}$; if the + factorization contains another power of $2$, then this is the exact local + conductor at $2$ and $N$ is the global conductor. + + \bprog + ? default(debuglevel, 1); + ? genus2red(x^6 + 3*x^3 + 63, 3) + (potential) stable reduction: [1, []] + reduction at p: [III{9}] page 184, [3, 3], f = 10 + %1 = [59049, Mat([3, 10]), x^6 + 3*x^3 + 63, [3, [1, []], + ["[III{9}] page 184", [3, 3]]]] + ? [N, FaN, T, V] = genus2red(x^3-x^2-1, x^2-x); \\ X_1(13), global reduction + p = 13 + (potential) stable reduction: [5, [Mod(0, 13), Mod(0, 13)]] + reduction at p: [I{0}-II-0] page 159, [], f = 2 + ? N + %3 = 169 + ? FaN + %4 = Mat([13, 2]) \\ in particular, good reduction at 2 ! + ? T + %5 = x^6 + 58*x^5 + 1401*x^4 + 18038*x^3 + 130546*x^2 + 503516*x + 808561 + ? V + %6 = [[13, [5, [Mod(0, 13), Mod(0, 13)]], ["[I{0}-II-0] page 159", []]]] + @eprog\noindent + We now first describe the format of the vector $V = V_{p}$ in the case where + $p$ was specified (local reduction at~$p$): it is a triple $[p, \var{stable}, + \var{red}]$. The component $\var{stable} = [\var{type}, \var{vecj}]$ contains + information about the stable reduction after a field extension; + depending on \var{type}s, the stable reduction is + + \item 1: smooth (i.e. the curve has potentially good reduction). The + Jacobian $J(C)$ has potentially good reduction. + + \item 2: an elliptic curve $E$ with an ordinary double point; \var{vecj} + contains $j$ mod $p$, the modular invariant of $E$. The (potential) + semi-abelian reduction of $J(C)$ is the extension of an elliptic curve (with + modular invariant $j$ mod $p$) by a torus. + + \item 3: a projective line with two ordinary double points. The Jacobian + $J(C)$ has potentially multiplicative reduction. + + \item 4: the union of two projective lines crossing transversally at three + points. The Jacobian $J(C)$ has potentially multiplicative reduction. + + \item 5: the union of two elliptic curves $E_{1}$ and $E_{2}$ intersecting + transversally at one point; \var{vecj} contains their modular invariants + $j_{1}$ and $j_{2}$, which may live in a quadratic extension of $\F_{p}$ + and need not be distinct. The Jacobian $J(C)$ has potentially good reduction, + isomorphic to the product of the reductions of $E_{1}$ and $E_{2}$. + + \item 6: the union of an elliptic curve $E$ and a projective line which has + an ordinary double point, and these two components intersect transversally + at one point; \var{vecj} contains $j$ mod $p$, the modular invariant of $E$. + The (potential) semi-abelian reduction of $J(C)$ is the extension of an + elliptic curve (with modular invariant $j$ mod $p$) by a torus. + + \item 7: as in type 6, but the two components are both singular. The + Jacobian $J(C)$ has potentially multiplicative reduction. + + The component $\var{red} = [\var{NUtype}, \var{neron}]$ contains two data + concerning the reduction at $p$ without any ramified field extension. + + The \var{NUtype} is a \typ{STR} describing the reduction at $p$ of $C$, + following Namikawa-Ueno, \emph{The complete classification of fibers in + pencils of curves of genus two}, Manuscripta Math., vol. 9, (1973), pages + 143-186. The reduction symbol is followed by the corresponding page number + or page range in this article. + + The second datum \var{neron} is the group of connected components (over an + algebraic closure of $\F_{p}$) of the N\'eron model of $J(C)$, given as a + finite abelian group (vector of elementary divisors). + \smallskip + If $p = 2$, the \var{red} component may be omitted altogether (and + replaced by \kbd{[]}, in the case where the program could not compute it. + When $p$ was not specified, $V$ is the vector of all $V_{p}$, for all + considered $p$. + + \misctitle{Notes about Namikawa-Ueno types} + + \item A lower index is denoted between braces: for instance, + \kbd{[I\obr2\cbr-II-5]} means \kbd{[I\_2-II-5]}. + + \item If $K$ and $K'$ are Kodaira symbols for singular fibers of elliptic + curves, then \kbd{[$K$-$K'$-m]} and \kbd{[$K'$-$K$-m]} are the same. + + We define a total ordering on Kodaira symbol by fixing $\kbd{I} < \kbd{I*} < + \kbd{II} < \kbd{II*}, \dots$. If the reduction type is the same, we order by + the number of components, e.g. $\kbd{I}_{2} < \kbd{I}_{4}$, etc. + Then we normalize our output so that $K \leq K'$. + + \item \kbd{[$K$-$K'$-$-1$]} is \kbd{[$K$-$K'$-$\alpha$]} in the notation of + Namikawa-Ueno. + + \item The figure \kbd{[2I\_0-m]} in Namikawa-Ueno, page 159, must be denoted + by \kbd{[2I\_0-(m+1)]}. + +Function: getabstime +Class: basic +Section: programming/specific +C-Name: getabstime +Prototype: l +Help: getabstime(): milliseconds of CPU time since startup. +Doc: returns the CPU time (in milliseconds) elapsed since \kbd{gp} startup. + This provides a reentrant version of \kbd{gettime}: + \bprog + my (t = getabstime()); + ... + print("Time: ", strtime(getabstime() - t)); + @eprog + For a version giving wall-clock time, see \tet{getwalltime}. + +Function: getcache +Class: basic +Section: programming/specific +C-Name: getcache +Prototype: +Help: getcache(): returns information about various auto-growing caches. For + each resource, we report its name, its size, the number of cache misses + (since the last extension) and the largest cache miss. +Doc: + returns information about various auto-growing caches. For + each resource, we report its name, its size, the number of cache misses + (since the last extension), the largest cache miss and the size of the cache + in bytes. + + The caches are initially empty, then set automatically to a small + inexpensive default value, then grow on demand up to some maximal value. + Their size never decreases, they are only freed on exit. + + The current caches are + + \item Hurwitz class numbers $H(D)$ for $|D| \leq N$, computed in time + $O(N^{3/2})$ using $O(N)$ space. + + \item Factorizations of small integers up to $N$, computed in time + $O(N^{1+\varepsilon})$ using $O(N\log N)$ space. + + \item Divisors of small integers up to $N$, computed in time + $O(N^{1+\varepsilon})$ using $O(N\log N)$ space. + + \item Coredisc's of negative integers down to $-N$, computed in time + $O(N^{1+\varepsilon})$ using $O(N)$ space. + + \item Primitive dihedral forms of weight $1$ and level up to $N$, + computed in time $O(N^{2+\varepsilon})$ and space $O(N^{2})$. + + \bprog + ? getcache() \\ on startup, all caches are empty + %1 = + [ "Factors" 0 0 0 0] + + [ "Divisors" 0 0 0 0] + + [ "H" 0 0 0 0] + + ["CorediscF" 0 0 0 0] + + [ "Dihedral" 0 0 0 0] + ? mfdim([500,1,0],0); \\ nontrivial computation + time = 540 ms. + ? getcache() + %3 = + [ "Factors" 50000 0 0 4479272] + + ["Divisors" 50000 1 100000 5189808] + + [ "H" 50000 0 0 400008] + + ["Dihedral" 1000 0 0 2278208] + @eprog + +Function: getenv +Class: basic +Section: programming/specific +C-Name: gp_getenv +Prototype: s +Help: getenv(s): value of the environment variable s, 0 if it is not defined. +Doc: return the value of the environment variable \kbd{s} if it is defined, otherwise return 0. + +Function: getheap +Class: basic +Section: programming/specific +C-Name: getheap +Prototype: +Help: getheap(): 2-component vector giving the current number of objects in + the heap and the space they occupy (in long words). +Doc: returns a two-component row vector giving the + number of objects on the heap and the amount of memory they occupy in long + words. Useful mainly for debugging purposes. + +Function: getlocalbitprec +Class: basic +Section: programming/specific +C-Name: getlocalbitprec +Prototype: lb +Help: getlocalbitprec(): returns the current dynamic bit precision. +Doc: returns the current dynamic bit precision. + %\syn{NO} + +Function: getlocalprec +Class: basic +Section: programming/specific +C-Name: getlocalprec +Prototype: lp +Help: getlocalprec(): returns the current dynamic precision, in decimal + digits. +Doc: returns the current dynamic precision, in decimal digits. + %\syn{NO} + +Function: getrand +Class: basic +Section: programming/specific +C-Name: getrand +Prototype: +Help: getrand(): current value of random number seed. +Doc: returns the current value of the seed used by the + pseudo-random number generator \tet{random}. Useful mainly for debugging + purposes, to reproduce a specific chain of computations. The returned value + is technical (reproduces an internal state array), and can only be used as an + argument to \tet{setrand}. + +Function: getstack +Class: basic +Section: programming/specific +C-Name: getstack +Prototype: l +Help: getstack(): current value of stack pointer avma. +Doc: returns the current value of $\kbd{top}-\kbd{avma}$, i.e.~the number of + bytes used up to now on the stack. Useful mainly for debugging purposes. + +Function: gettime +Class: basic +Section: programming/specific +C-Name: gettime +Prototype: l +Help: gettime(): milliseconds of CPU time used since the last call to gettime. +Doc: returns the CPU time (in milliseconds) used since either the last call to + \kbd{gettime}, or to the beginning of the containing GP instruction (if + inside \kbd{gp}), whichever came last. + + For a reentrant version, see \tet{getabstime}. + + For a version giving wall-clock time, see \tet{getwalltime}. + +Function: getwalltime +Class: basic +Section: programming/specific +C-Name: getwalltime +Prototype: +Help: getwalltime(): time (in milliseconds) since the UNIX Epoch. +Doc: returns the time (in milliseconds) elapsed since + 00:00:00 UTC Thursday 1, January 1970 (the Unix epoch). + \bprog + my (t = getwalltime()); + ... + print("Time: ", strtime(getwalltime() - t)); + @eprog + +Function: global +Class: basic +Section: programming/specific +Obsolete: 2007-10-03 +Help: global(list of variables): obsolete. Scheduled for deletion. +Doc: obsolete. Scheduled for deletion. + % \syn{NO} + +Function: halfgcd +Class: basic +Section: number_theoretical +C-Name: ghalfgcd +Prototype: GG +Help: halfgcd(x,y): return a vector [M, [a,b]~], where M is an invertible 2x2 + matrix such that M*[x,y]~ = [a,b]~, where b is small. More precisely, + if x,y are integers, we have b < sqrt(max(|x|,|y|)) <= a. If x,y + are polynomials, we have deg b < ceil((max(|x|,|y|))/2) <= deg a. +Doc: + Let inputs $x$ and $y$ be both integers, or both polynomials in the same + variable. Return a vector \kbd{[M, [a,b]\til]}, where $M$ is an invertible + $2\times 2$ matrix such that \kbd{M*[x,y]\til = [a,b]\til}, where $b$ is + small. More precisely, + + \item polynomial case: $\det M$ has degree $0$ and we + have $$\deg a \geq \ceil{\max(\deg x,\deg y))/2} > \deg b.$$ + + \item integer case: $\det M = \pm 1$ and we have + $$a \geq \ceil{\sqrt{\max(|x|,|y|)}} > b.$$ + Assuming $x$ and $y$ are nonnegative, then $M^{-1}$ has nonnegative + coefficients, and $\det M$ is equal to the sign of both main diagonal terms + $M[1,1]$ and $M[2,2]$. + +Function: hammingweight +Class: basic +Section: combinatorics +C-Name: hammingweight +Prototype: lG +Help: hammingweight(x): returns the Hamming weight of x. +Doc: + If $x$ is a \typ{INT}, return the binary Hamming weight of $|x|$. Otherwise + $x$ must be of type \typ{POL}, \typ{VEC}, \typ{COL}, \typ{VECSMALL}, or + \typ{MAT} and the function returns the number of nonzero coefficients of + $x$. + \bprog + ? hammingweight(15) + %1 = 4 + ? hammingweight(x^100 + 2*x + 1) + %2 = 3 + ? hammingweight([Mod(1,2), 2, Mod(0,3)]) + %3 = 2 + ? hammingweight(matid(100)) + %4 = 100 + @eprog + +Function: harmonic +Class: basic +Section: combinatorics +C-Name: harmonic0 +Prototype: UDG +Help: harmonic(n,{r=1}): generalized harmonic number of index n in power r. +Doc: generalized harmonic number of index $n \geq 0$ in power $r$, as a rational + number. If $r = 1$ (or omitted), this is the harmonic number + $$ H_{n} = \sum_{i = 1}^{n} \dfrac{1}{i}.$$ + In general, this is + $$ H_{n,r} = \sum_{i = 1}^{n} \dfrac{1}{i^{r}}.$$ + The function runs in time $\tilde{O}(r n)$, essentially linear in the + size of the output. + \bprog + ? harmonic(0) + %1 = 0 + ? harmonic(1) + %2 = 1 + ? harmonic(10) + %3 = 7381/2520 + ? harmonic(10, 2) + %4 = 1968329/1270080 + ? harmonic(10, -2) + %5 = 385 + @eprog\noindent Note that the numerator and denominator are of order + $\exp((r+o(1))n)$ and this will overflow for large $n$. To obtain $H_{n}$ as a + floating point number, use $H_{n} = \kbd{psi}(n+1) + \kbd{Euler}$. +Variant: Also available is \fun{GEN}{harmonic}{ulong n} for $r = 1$. + +Function: hgmalpha +Class: basic +Section: hypergeometric_motives +C-Name: hgmalpha +Prototype: G +Help: hgmalpha(H): returns the alpha and beta parameters of the hypergeometric + motive template H. +Doc: returns the alpha and beta parameters of the hypergeometric motive + template $H$. + \bprog + ? H = hgminit([5]); \\ template given by cyclotomic parameters + ? hgmalpha(H) + %2 = [[1/5, 2/5, 3/5, 4/5], [0, 0, 0, 0]] + @eprog + +Function: hgmbydegree +Class: basic +Section: hypergeometric_motives +C-Name: hgmbydegree +Prototype: L +Help: hgmbydegree(n): outputs [L(0),...,L(n-1)] where L(w) is the list of + cyclotomic parameters of all possible hypergeometric motive templates of + degree n and weight w. +Doc: outputs $[L(0),...,L(n-1)]$ where $L(w)$ is the list of + cyclotomic parameters of all possible hypergeometric motive templates of + degree $n$ and weight $w$. + +Function: hgmcoef +Class: basic +Section: hypergeometric_motives +C-Name: hgmcoef +Prototype: GGG +Help: hgmcoef(H,t,n): (H,t) being a hypergeometric motive, returns the + n-th coefficient of its L-function. +Doc: $(H,t)$ being a hypergeometric motive, returns the + $n$-th coefficient of its $L$-function. This is not implemented for wild + primes $p$ and will raise an exception if such a $p$ divides~$n$. + +Function: hgmcoefs +Class: basic +Section: hypergeometric_motives +C-Name: hgmcoefs +Prototype: GGL +Help: hgmcoefs(H,t,n): (H,t) being a hypergeometric motive, returns the + first n coefficients of its L-function, where Euler factors at wild primes + are set to 1. +Doc: $(H,t)$ being a hypergeometric motive, returns the + first $n$ coefficients of its $L$-function, where Euler factors at wild primes + are set to 1. The argument $t$ may be replaced by $[t,\var{bad}]$ + where \var{bad} is a vector of pairs $[p,L_{p}]$, $p$ being a prime and $L_{p}$ + being the corresponding local Euler factor, overriding the default. + + If you hope that the wild Euler factors can be computed not too slowly + from the functional equation, you can also set \kbd{L=lfunhgm(H,t)}, and then + \kbd{lfunan(L,n)}, and then the Euler factors at wild primes should + be correct. + +Function: hgmcyclo +Class: basic +Section: hypergeometric_motives +C-Name: hgmcyclo +Prototype: G +Help: hgmcyclo(H): returns the cyclotomic parameters (D,E) of the + hypergeometric motive template H. +Doc: returns the cyclotomic parameters $(D,E)$ of the + hypergeometric motive template $H$. + \bprog + \\ template given by alpha (implied beta is [0,0,0,0]) + ? H = hgminit([1/5, 2/5, 3/5, 4/5]); + ? hgmcyclo(H) + %3 = [Vecsmall([5]), Vecsmall([1, 1, 1, 1])] + ? apply(Vec, %) \\ for readability + %4 = [[5], [1, 1, 1, 1]] + @eprog + +Function: hgmeulerfactor +Class: basic +Section: hypergeometric_motives +C-Name: hgmeulerfactor +Prototype: GGLD& +Help: hgmeulerfactor(H,t,p,{&e}): (H,t) being a hypergeometric motive, + returns the Euler factor P_p at the prime p; if present, set e to the valuation + of the conductor at p. +Doc: $(H,t)$ being a hypergeometric motive, returns the inverse of its + Euler factor at the prime $p$ and the exponent $e$ of the conductor at $p$. + This is not implemented when $p$ is a wild prime: the function returns $0$ and + sets $e$ to $-1$. Caveat: contrary to \kbd{lfuneuler}, this function returns + the \emph{inverse} of the Euler factor, given by a polynomial $P_{p}$ such that + the Euler factor is $1 / P_{p}(p^{-s})$. + \bprog + ? H = hgminit([5]); \\ cyclotomic parameters [5] and [1,1,1,1] + ? hgmeulerfactor(H, 1/2, 3) + %2 = 729*x^4 + 135*x^3 + 45*x^2 + 5*x + 1 + ? hgmeulerfactor(H, 1/2, 3, &e) + %3 = 729*x^4 + 135*x^3 + 45*x^2 + 5*x + 1 + ? e + %4 = 0 + ? hgmeulerfactor(H, 1/2, 2, &e) + %5 = -x + 1 + ? e + %6 = 3 + ? hgmeulerfactor(H, 1/2, 5) + %7 = 0 \\ 5 is wild + @eprog + + If the conductor is small, the wild Euler factors can be computed + from the functional equation: set \kbd{L = lfunhgm(H,t)} (the complexity + should be roughly proportional to the conductor) then + the \kbd{lfuneuler} function should give you the correct Euler factors + at all primes: + \bprog + ? L = lfunhgm(H, 1/2); + time = 790 ms. \\ fast in this case, only 5 is wild + ? lfunparams(L) \\ ... and the conductor 5000 is small + %8 = [5000, 4, [-1, 0, 0, 1]] + ? lfuneuler(L, 5) + %9 = 1 \\ trivial Euler factor + + ? L = lfunhgm(H, 1/64); lfunparams(L) + time = 20,122 ms. \\ slower: the conductor is larger + %10 = [525000, 4, [-1, 0, 0, 1]] + + ? L = lfunhgm(H, 1/128); lfunparams(L) + time = 2min, 16,205 ms. \\ even slower, etc. + %11 = [3175000, 4, [-1, 0, 0, 1]] + @eprog + +Function: hgmgamma +Class: basic +Section: hypergeometric_motives +C-Name: hgmgamma +Prototype: G +Help: hgmgamma(H): returns the gamma vector of the hypergeometric motive + template H. +Doc: returns the gamma vector of the hypergeometric motive + template $H$. + \bprog + ? H = hgminit([5]); + ? hgmgamma(H) + %2 = Vecsmall([-5, 0, 0, 0, 1]) + @eprog + +Function: hgminit +Class: basic +Section: hypergeometric_motives +C-Name: hgminit +Prototype: GDG +Help: hgminit(a,{b}): Create the template for a hypergeometric + motive with parameters a and possibly b. The format of the parameters may + be alpha: Galois invariant lists of rational numbers a=alpha and b=beta; + or cyclo: lists A and B of positive integers corresponding to alpha and beta; + or gamma: list of cn such that the hypergeometric quotient is prod_n(x^n-1)^cn. +Doc: Create the template for the hypergeometric motive with parameters + $a$ and possibly $b$. The format of the parameters may be + + \item alpha: lists of rational numbers $a=(\alpha_{j})$ and + $b=(\beta_{k})$ of the same length (and defined over~$\Q$); if $b$ is + omitted, we take it to be $(0,\dots,0)$. + + \item cyclo: lists $a=D$ and $b=E$ of positive integers corresponding + to the denominators of the $(\alpha_{i})$ and $(\beta_{i})$; if $b$ is omitted + we take it to be $(1,\dots,1)$. This is the simplest and most compact input + format. + + \item gamma: list of $\gamma_{n}$ such that the + $\prod_{j}(x-\exp(2\pi i\alpha_{j})) / \prod_{k}(x-\exp(2\pi i\beta_{k})) + = \prod_{n}(x^{n}-1)^{\gamma_{n}}$. + + The hypergeometric motive itself is given by a pair $(H,t)$, where $H$ + is a template as above and $t\in \Q^{*}$. Note that the motives given by + $(\alpha, \beta; t)$ and $(\beta,\alpha; 1/t)$ are identical. + + \bprog + ? H = hgminit([5]); \\ template given by cyclotomic parameters 5 and 1,1,1,1 + ? L = lfunhgm(H, 1); \\ global L-function attached to motive (H,1) + ? lfunparams(L) + %3 = [25, 4, [0, 1]] + + ? hgmalpha(H) + %4 = [[1/5, 2/5, 3/5, 4/5], [0, 0, 0, 0]] + ? hgmgamma(H) + %5 = Vecsmall([-5, 0, 0, 0, 1]) + @eprog + +Function: hgmissymmetrical +Class: basic +Section: hypergeometric_motives +C-Name: hgmissymmetrical +Prototype: lG +Help: hgmissymmetrical(H): is the hypergeometric motive template H symmetrical + at t=1? +Doc: is the hypergeometric motive template $H$ symmetrical + at $t=1$? This means that the $\alpha_{j}$ and $\beta_{k}$ defining the + template are obtained from one another by adding $1/2$ (modulo $1$), see + \kbd{hgmtwist}. + \bprog + ? H = hgminit([2,2]); + ? hgmalpha(H) + %2 = [[1/2, 1/2], [0, 0]] + ? hgmissymmetrical(H) + %3 = 1 \\ this template is symmetrical + + ? H = hgminit([5]); + ? hgmalpha(H) + %5 = [[1/5, 2/5, 3/5, 4/5], [0, 0, 0, 0]] + ? hgmissymmetrical(H) + %6 = 1 \\ this one is not + @eprog + +Function: hgmparams +Class: basic +Section: hypergeometric_motives +C-Name: hgmparams +Prototype: G +Help: hgmparams(H): H being a hypergeometric motive template, returns + [d, w, [P, T], M], where d is the degree, w the weight, + P the Hodge polynomial and T the Tate twist number (so that the Hodge + function itself is P/x^T); finally M is the so-called M-value. +Doc: $H$ being a hypergeometric motive template, returns + $[d,w,[P,T], M]$, where $d$ is the degree, $w$ the weight, + $P$ the Hodge polynomial, and $T$ the Tate twist number (so that the Hodge + function itself is $P/x^{T}$); finally the normalizing factor $M$ is the + so-called $M$-value, $M = \prod_{n} n^{n\gamma_{n}}$. + +Function: hgmtwist +Class: basic +Section: hypergeometric_motives +C-Name: hgmtwist +Prototype: G +Help: hgmtwist(H): twist by 1/2 of alpha and beta of the hypergeometric motive + template H. +Doc: twist by $1/2$ of alpha and beta of the hypergeometric motive + template $H$. + \bprog + ? H = hgminit([5]); + ? hgmalpha(H) + %2 = [[1/5, 2/5, 3/5, 4/5], [0, 0, 0, 0]] + ? H2 = hgmtwist(H); + ? hgmalpha(H2) + %4 = [[1/10, 3/10, 7/10, 9/10], [1/2, 1/2, 1/2, 1/2]] + @eprog\noindent The template is symmetrical (\kbd{hgmissymmetrical}) + if it is equal to its twist. + +Function: hilbert +Class: basic +Section: number_theoretical +C-Name: hilbert +Prototype: lGGDG +Help: hilbert(x,y,{p}): Hilbert symbol at p of x,y. +Doc: \idx{Hilbert symbol} of $x$ and $y$ modulo the prime $p$, $p=0$ meaning + the place at infinity (the result is undefined if $p\neq 0$ is not prime). + + It is possible to omit $p$, in which case we take $p = 0$ if both $x$ + and $y$ are rational, or one of them is a real number. And take $p = q$ + if one of $x$, $y$ is a \typ{INTMOD} modulo $q$ or a $q$-adic. (Incompatible + types will raise an error.) + +Function: hyperellchangecurve +Class: basic +Section: elliptic_curves +C-Name: hyperellchangecurve +Prototype: GG +Help: hyperellchangecurve(C,m): C being a nonsingular + hyperelliptic model of a curve, apply the change of coordinate + given by m. + C can be given either by a squarefree polynomial P such that + C:y^2=P(x) or by a vector [P,Q] such that C:y^2+Q(x)*y=P(x) and Q^2+4P is + squarefree. +Doc: + $C$ being a nonsingular hyperelliptic model of a curve, + apply the change of coordinate given by $m = [e, [a,b;c,d], H]$. + + If $(x,y)$ is a point on the new model, the corresponding + point $(X,Y)$ on $C$ is given by + $$ + X = (a*x + b) / (c*x + d), \quad + Y = e (y + H(x)) / (c*x + d)^{g+1}. + $$ + + $C$ can be given either by a squarefree polynomial $P$ such that + $C: y^{2} = P(x)$ or by a vector $[P,Q]$ such that + $C: y^{2} + Q(x)\*y = P(x)$ and $Q^{2}+4\*P$ is squarefree. + +Function: hyperellcharpoly +Class: basic +Section: elliptic_curves +C-Name: hyperellcharpoly +Prototype: G +Help: hyperellcharpoly(X): X being a nonsingular hyperelliptic curve defined + over a finite field, return the characteristic polynomial of the Frobenius + automorphism. X can be given either by a squarefree polynomial P such that + X:y^2=P(x) or by a vector [P,Q] such that X:y^2+Q(x)*y=P(x) and Q^2+4P is + squarefree. +Doc: + $X$ being a nonsingular hyperelliptic curve defined over a finite field, + return the characteristic polynomial of the Frobenius automorphism. + $X$ can be given either by a squarefree polynomial $P$ such that + $X: y^{2} = P(x)$ or by a vector $[P,Q]$ such that + $X: y^{2} + Q(x)\*y = P(x)$ and $Q^{2}+4\*P$ is squarefree. + +Function: hyperelldisc +Class: basic +Section: elliptic_curves +C-Name: hyperelldisc +Prototype: G +Help: hyperelldisc(X): X being a nonsingular hyperelliptic model of a curve, + defined over a field of characteristic distinct from 2, returns its discriminant. + X can be given either by a squarefree polynomial P such that + X:y^2=P(x) or by a vector [P,Q] such that X:y^2+Q(x)*y=P(x) and Q^2+4P is + squarefree. +Doc: + $X$ being a nonsingular hyperelliptic model of a curve, + defined over a field of characteristic distinct from 2, returns its discriminant. + $X$ can be given either by a squarefree polynomial $P$ such that + $X$ has equation $y^{2} = P(x)$ or by a vector $[P,Q]$ such that + $X$ has equation $y^{2} + Q(x)\*y = P(x)$ and $Q^{2}+4\*P$ is squarefree. + \bprog + ? hyperelldisc([x^3,1]) + %1 = -27 + ? hyperelldisc(x^5+1) + %2 = 800000 + @eprog + +Function: hyperellisoncurve +Class: basic +Section: elliptic_curves +C-Name: hyperellisoncurve +Prototype: iGG +Help: hyperellisoncurve(X,p): X being a nonsingular hyperelliptic model of a curve, + test whether the point p is on the curve. + X can be given either by a squarefree polynomial P such that + X:y^2=P(x) or by a vector [P,Q] such that X:y^2+Q(x)*y=P(x) and Q^2+4P is + squarefree. +Doc: + $X$ being a nonsingular hyperelliptic model of a curve, test whether the + point $p$ is on the curve. + + $X$ can be given either by a squarefree polynomial $P$ such that + $X: y^{2} = P(x)$ or by a vector $[P,Q]$ such that + $X: y^{2} + Q(x)\*y = P(x)$ and $Q^{2}+4\*P$ is squarefree. + \bprog + ? W = [2*x^6+3*x^5+x^4+x^3-x,x^3+1]; p = [px, py] = [1/3,-14/27]; + ? hyperellisoncurve(W, p) + %2 = 1 + ? [Px,Qx]=subst(W,x,px); py^2+py*Qx == Px + %3 = 1 + @eprog + +Function: hyperellminimaldisc +Class: basic +Section: elliptic_curves +C-Name: hyperellminimaldisc +Prototype: GDG +Help: hyperellminimaldisc(C,{pr}): C being a nonsingular integral + hyperelliptic model of a curve, return the minimal discrminant of an integral + model of C. If pr is given, it must be a list of primes and the discriminant + is then only garanteed minimal at the elements of pr. + C can be given either by a squarefree polynomial P such that + C:y^2=P(x) or by a vector [P,Q] such that C:y^2+Q(x)*y=P(x) and Q^2+4P is + squarefree. +Doc: + $C$ being a nonsingular integral hyperelliptic model of a curve, + return the minimal discriminant of an integral model of $C$. + If $pr$ is given, it must be a list of primes and + the discriminant is then only garanteed minimal at the elements of $pr$. + $C$ can be given either by a squarefree polynomial $P$ such that + $C: y^{2} = P(x)$ or by a vector $[P,Q]$ such that + $C: y^{2} + Q(x)\*y = P(x)$ and $Q^{2}+4\*P$ is squarefree. + \bprog + ? W = [x^6+216*x^3+324,0]; + ? D = hyperelldisc(W) + %2 = 1828422898924853919744000 + ? M = hyperellminimaldisc(W) + %4 = 29530050606000 + @eprog + +Function: hyperellminimalmodel +Class: basic +Section: elliptic_curves +C-Name: hyperellminimalmodel +Prototype: GD&DG +Help: hyperellminimalmodel(C,{&m},{pr}): C being a nonsingular integral + hyperelliptic model of a curve, return an integral model of C with minimal + discriminant. If pr is given, it must be a list of primes and the model is + then only garanteed minimal at the elements of pr. + C can be given either by a squarefree polynomial P such that + C:y^2=P(x) or by a vector [P,Q] such that C:y^2+Q(x)*y=P(x) and Q^2+4P is + squarefree. +Doc: + $C$ being a nonsingular integral hyperelliptic model of a curve, + return an integral model of $C$ with minimal discriminant. + If $pr$ is given, it must be a list of primes and + the model is then only garanteed minimal at the elements of $pr$. + If present, $m$ is set to the mapping from the original model to the new + one: a three-component vector $[e,[a,b;c,d],H]$ such that + if $(x,y)$ is a point on $W$, the corresponding point on $C$ is given by + $$ x_{C} = (a*x+b)/(c*x+d) $$ + $$ y_{C} = (e*y+H(x))/(c*x+d)^{g+1} $$ + where $g$ is the genus. + $C$ can be given either by a squarefree polynomial $P$ such that + $C: y^{2} = P(x)$ or by a vector $[P,Q]$ such that + $C: y^{2} + Q(x)\*y = P(x)$ and $Q^{2}+4\*P$ is squarefree. + \bprog + ? W = [x^6+216*x^3+324,0]; + ? D = hyperelldisc(W) + %2 = 1828422898924853919744000 + ? Wn = hyperellminimalmodel(W,&M) + %3 = [2*x^6+18*x^3+1,x^3]; + ? M + %4 = [18, [3, 0; 0, 1], 9*x^3] + ? hyperelldisc(Wn) + %5 = 29530050606000 + ? hyperellchangecurve(W, M) + %6 = [2*x^6+18*x^3+1,x^3] + @eprog + +Function: hyperellordinate +Class: basic +Section: elliptic_curves +C-Name: hyperellordinate +Prototype: GG +Help: hyperellordinate(H,x): y-coordinates corresponding to x-ordinate x on + hyperelliptic curve H. +Doc: + gives a 0, 1 or 2-component vector containing + the $y$-coordinates of the points of the curve $H$ having $x$ as + $x$-coordinate. + +Function: hyperellpadicfrobenius +Class: basic +Section: elliptic_curves +C-Name: hyperellpadicfrobenius0 +Prototype: GGL +Help: hyperellpadicfrobenius(Q,q,n): Q being a rational polynomial of degree + d and X being the curve defined by y^2=Q(x), return the matrix of the + Frobenius at the prime q >= d in the standard basis of H^1_dR(X) to absolute + q-adic precision q^n; q may also be of the form [T,p] where T is an integral + polynomial which is irreducible mod p. +Doc: + Let $X$ be the curve defined by $y^{2}=Q(x)$, where $Q$ is a polynomial of + degree $d$ over $\Q$ and $q\ge d$ is a prime such that $X$ has good reduction + at $q$. Return the matrix of the Frobenius endomorphism $\varphi$ on the + crystalline module $D_{p}(X) = \Q_{p} \otimes H^{1}_{dR}(X/\Q)$ with respect to the + basis of the given model $(\omega, x\*\omega,\ldots,x^{g-1}\*\omega)$, where + $\omega = dx/(2\*y)$ is the invariant differential, where $g$ is the genus of + $X$ (either $d=2\*g+1$ or $d=2\*g+2$). The characteristic polynomial of + $\varphi$ is the numerator of the zeta-function of the reduction of the curve + $X$ modulo $q$. The matrix is computed to absolute $q$-adic precision $q^{n}$. + + Alternatively, $q$ may be of the form $[T,p]$ where $p$ is a prime, + $T$ is a polynomial with integral coefficients whose projection to + $\F_{p}[t]$ is irreducible, $X$ is defined over $K = \Q[t]/(T)$ and has good + reduction to the finite field $\F_{q} = \F_{p}[t]/(T)$. The matrix of + $\varphi$ on $D_{q}(X) = \Q_{q} \otimes H^{1}_{dR}(X/K)$ is computed + to absolute $p$-adic precision $p^{n}$. + + \bprog + ? M=hyperellpadicfrobenius(x^5+'a*x+1,['a^2+1,3],10); + ? liftall(M) + [48107*a + 38874 9222*a + 54290 41941*a + 8931 39672*a + 28651] + + [ 21458*a + 4763 3652*a + 22205 31111*a + 42559 39834*a + 40207] + + [ 13329*a + 4140 45270*a + 25803 1377*a + 32931 55980*a + 21267] + + [15086*a + 26714 33424*a + 4898 41830*a + 48013 5913*a + 24088] + ? centerlift(simplify(liftpol(charpoly(M)))) + %8 = x^4+4*x^2+81 + ? hyperellcharpoly((x^5+Mod(a,a^2+1)*x+1)*Mod(1,3)) + %9 = x^4+4*x^2+81 + @eprog +Variant: The functions + \fun{GEN}{hyperellpadicfrobenius}{GEN H, ulong p, long n} + and + \fun{GEN}{nfhyperellpadicfrobenius}{GEN H, GEN T, ulong p, long n} are also + available. + +Function: hyperellratpoints +Class: basic +Section: elliptic_curves +C-Name: hyperellratpoints +Prototype: GGD0,L, +Help: hyperellratpoints(X,h,{flag=0}): X being a nonsingular hyperelliptic + curve given by an rational model, return a vector containing the affine + rational points on the curve of naive height less than h. + If fl=1, stop as soon as a point is found. + X can be given either by a squarefree polynomial P such that + X:y^2=P(x) or by a vector [P,Q] such that X:y^2+Q(x)y=P(x) and Q^2+4P is + squarefree. +Doc: $X$ being a nonsingular hyperelliptic curve given by an rational model, + return a vector containing the affine rational points on the curve of naive + height less than $h$. If $\fl=1$, stop as soon as a point is found; return + either an empty vector or a vector containing a single point. + + $X$ is given either by a squarefree polynomial $P$ such that $X: y^{2}=P(x)$ + or by a vector $[P,Q]$ such that $X: y^{2}+Q(x)\*y=P(x)$ and $Q^{2}+4\*P$ is + squarefree. + + \noindent The parameter $h$ can be + + \item an integer $H$: find the points $[n/d,y]$ whose abscissas $x = n/d$ have + naive height (= $\max(|n|, d)$) less than $H$; + + \item a vector $[N,D]$ with $D\leq N$: find the points $[n/d,y]$ with + $|n| \leq N$, $d \leq D$. + + \item a vector $[N,[D_{1},D_{2}]]$ with $D_{1} 0$. Return an integral model of $C$ with the same discriminant + but small coefficients, using Cremona-Stoll reduction. + + The optional argument $m$ is set to the mapping from the original model to + the new one, given by a three-component vector \kbd{[1,[a,b;c,d],H]} + such that $a*d-b*c=1$ and if $(x,y)$ is a point on $W$, the corresponding + point $(X,Y)$ on $C$ is given by + $$ + X = (a*x + b) / (c*x + d), \quad + Y = (y + H(x)) / (c*x + d)^{g+1}. + $$ + $C$ can be given either by a squarefree polynomial $P$ such that + $C: y^{2} = P(x)$ or by a vector $[P,Q]$ such that + $C: y^{2} + Q(x)\*y = P(x)$ and $Q^{2}+4\*P$ is squarefree. + \bprog + ? P = 1001*x^4 + 3704*x^3 + 5136*x^2 + 3163*x + 730; + ? hyperellred(P, &m) + %2 = [x^3 + 1, 0] + ? hyperellchangecurve(P, m) + %3 = [x^3 + 1, 0] + @eprog +Variant: + Also available is + \fun{GEN}{ZX_hyperellred}{GEN P, GEN *M} where $C: y^{2} = P(x)$ and *M is + set to \kbd{[a,b;c,d]} + +Function: hypergeom +Class: basic +Section: transcendental +C-Name: hypergeom +Prototype: DGDGGp +Help: hypergeom({N},{D},z): general hypergeometric function, where + N and D are the vector of parameters in the numerator and denominator + respectively, evaluated at the argument z. +Doc: general hypergeometric function, where \kbd{N} and \kbd{D} are + the vector of parameters in the numerator and denominator respectively, + evaluated at the argument $z$, which may be complex, $p$-adic or a power + series. + + This function implements hypergeometric functions + $$_{p}F_{q}((a_{i})_{1\le i\le p},(b_{j})_{1\le j\le q};z) + = \sum_{n\ge0}\dfrac{\prod_{1\le i\le p}(a_{i})_{n}}{\prod_{1\le j\le q}(b_{j})_{n}} + \dfrac{z^{n}}{n!}\;,$$ + where $(a)_{n}=a(a+1)\cdots(a+n-1)$ is the rising Pochhammer symbol. For this + to make sense, none of the $b_{j}$ must be a negative or zero integer. The + corresponding general GP command is + \bprog + hypergeom([a1,a2,...,ap], [b1,b2,...,bq], z) + @eprog\noindent Whenever $p = 1$ or $q = 1$, a one-element vector can be + replaced by the element it contains. Whenever $p = 0$ or $q = 0$, an empty + vector can be omitted. For instance hypergeom(,b,z) computes + $_{0}F_{1}(;b;z)$. + + The non-archimedean cases ($z$ a $p$-adic or power series) are handled + trivially. We now discuss the case of a complex $z$; we distinguish three + kinds of such functions according to their radius of convergence $R$: + + \item $q\ge p$: $R = \infty$. + + \item $q=p-1$: $R=1$. Nonetheless, by integral representations, $_{p}F_{q}$ + can be analytically continued outside the disc of convergence. + + \item $q\le p-2$: $R=0$. By integral representations, one can make sense of + the function in a suitable domain, by analytic continuation. + + The list of implemented functions and their domain of validity in + our implementation is as follows: + + \kbd{F01}: \kbd{hypergeom(,a,z)} (or \kbd{[a]}). + This is essentially a Bessel function and computed as such. $R=\infty$. + + \kbd{F10}: \kbd{hypergeom(a,,z)} + This is $(1-z)^{-a}$. + + \kbd{F11}: \kbd{hypergeom(a,b,z)} is the Kummer confluent hypergeometric + function, computed by summing the series. $R=\infty$ + + \kbd{F20}: \kbd{hypergeom([a,b],,z)}. $R=0$, computed as + $$\dfrac{1}{\Gamma(a)}\int_{0}^{\infty} t^{a-1}(1-zt)^{-b}e^{-t}\,dt\;.$$ + + \kbd{F21}: \kbd{hypergeom([a,b],c,z)} (or \kbd{[c]}). + $R=1$, extended by + $$\dfrac{\Gamma(c)}{\Gamma(b)\Gamma(c-b)} + \int_{0}^{1} t^{b-1}(1-t)^{c-b-1}(1-zt)^{a}\,dt\;.$$ + This is Gauss's Hypergeometric function, and almost all of the implementation + work is done for this function. + + \kbd{F31}: \kbd{hypergeom([a,b,c],d,z)} (or \kbd{[d]}). $R=0$, computed as + $$\dfrac{1}{\Gamma(a)}\int_{0}^{\infty} t^{a-1}e^{-t} + {}_{2}F_{1}(b,c;d;tz)\,dt\;.$$ + + \kbd{F32}: \kbd{hypergeom([a,b,c],[d,e],z)}. $R=1$, extended by + $$\dfrac{\Gamma(e)}{\Gamma(c)\Gamma(e-c)} + \int_{0}^{1}t^{c-1}(1-t)^{e-c-1}{}_{2}F_{1}(a,b;d;tz)\,dt\;.$$ + + For other inputs: if $R=\infty$ or $R=1$ and $|z| < 1- \varepsilon$ is not + too close to the circle of convergence, we simply sum the series. + + \bprog + ? hypergeom([3,2], 3.4, 0.7) \\ 2F1(3,2; 3.4; 0.7) + %1 = 7.9999999999999999999999999999999999999 + ? a=5/3; T1=hypergeom([1,1,1],[a,a],1) \\ 3F2(1,1,1; a,a; 1) + %2 = 3.1958592952314032651578713968927593818 + ? T2=hypergeom([2,1,1],[a+1,a+1],1) + %3 = 1.6752931349345765309211012564734179541 + ? T3=hypergeom([2*a-1,1,1],[a+1,a+1],1) + %4 = 1.9721037126267142061807688820853354440 + ? T1 + (a-1)^2/(a^2*(2*a-3)) * (T2-2*(a-1)*T3) \\ + - gamma(a)^2/((2*a-3)*gamma(2*a-2)) + %5 = -1.880790961315660013 E-37 \\ ~ 0 + @eprog\noindent This identity is due to Bercu. + +Function: hyperu +Class: basic +Section: transcendental +C-Name: hyperu +Prototype: GGGp +Help: hyperu(a,b,z): U-confluent hypergeometric function. +Doc: $U$-confluent hypergeometric function with complex + parameters $a, b, z$. Note that $_{2}F_{0}(a,b,z) + = (-z)^{-a}U(a, a+1-b, -1/z)$, + \bprog + ? hyperu(1, 3/2, I) + %1 = 0.23219... - 0.80952...*I + ? -I * hypergeom([1, 1+1-3/2], [], -1/I) + %2 = 0.23219... - 0.80952...*I + @eprog + +Function: idealadd +Class: basic +Section: number_fields +C-Name: idealadd +Prototype: GGG +Help: idealadd(nf,x,y): sum of two ideals x and y in the number field + defined by nf. +Doc: sum of the two ideals $x$ and $y$ in the number field $\var{nf}$. The + result is given in HNF. + \bprog + ? K = nfinit(x^2 + 1); + ? a = idealadd(K, 2, x + 1) \\ ideal generated by 2 and 1+I + %2 = + [2 1] + + [0 1] + ? pr = idealprimedec(K, 5)[1]; \\ a prime ideal above 5 + ? idealadd(K, a, pr) \\ coprime, as expected + %4 = + [1 0] + + [0 1] + @eprog\noindent + This function cannot be used to add arbitrary $\Z$-modules, since it assumes + that its arguments are ideals: + \bprog + ? b = Mat([1,0]~); + ? idealadd(K, b, b) \\ only square t_MATs represent ideals + *** idealadd: nonsquare t_MAT in idealtyp. + ? c = [2, 0; 2, 0]; idealadd(K, c, c) \\ nonsense + %6 = + [2 0] + + [0 2] + ? d = [1, 0; 0, 2]; idealadd(K, d, d) \\ nonsense + %7 = + [1 0] + + [0 1] + + @eprog\noindent In the last two examples, we get wrong results since the + matrices $c$ and $d$ do not correspond to an ideal: the $\Z$-span of their + columns (as usual interpreted as coordinates with respect to the integer basis + \kbd{K.zk}) is not an $\Z_{K}$-module. To add arbitrary $\Z$-modules generated + by the columns of matrices $A$ and $B$, use \kbd{mathnf(concat(A,B))}. + +Function: idealaddtoone +Class: basic +Section: number_fields +C-Name: idealaddtoone0 +Prototype: GGDG +Help: idealaddtoone(nf,x,{y}): if y is omitted, when the sum of the ideals + in the number field K defined by nf and given in the vector x is equal to + Z_K, gives a vector of elements of the corresponding ideals who sum to 1. + Otherwise, x and y are ideals, and if they sum up to 1, find one element in + each of them such that the sum is 1. +Doc: $x$ and $y$ being two co-prime + integral ideals (given in any form), this gives a two-component row vector + $[a,b]$ such that $a\in x$, $b\in y$ and $a+b=1$. + + The alternative syntax $\kbd{idealaddtoone}(\var{nf},v)$, is supported, where + $v$ is a $k$-component vector of ideals (given in any form) which sum to + $\Z_{K}$. This outputs a $k$-component vector $e$ such that $e[i]\in x[i]$ for + $1\le i\le k$ and $\sum_{1\le i\le k}e[i]=1$. + +Function: idealappr +Class: basic +Section: number_fields +C-Name: idealappr0 +Prototype: GGD0,L, +Help: idealappr(nf,x,{flag}): x being a fractional ideal, gives an element + b such that v_p(b)=v_p(x) for all prime ideals p dividing x, and v_p(b)>=0 + for all other p; x may also be a prime ideal factorization with possibly + zero exponents. flag is deprecated (ignored), kept for backward compatibility. +Doc: if $x$ is a fractional ideal + (given in any form), gives an element $\alpha$ in $\var{nf}$ such that for + all prime ideals $\goth{p}$ such that the valuation of $x$ at $\goth{p}$ is + nonzero, we have $v_{\goth{p}}(\alpha)=v_{\goth{p}}(x)$, and + $v_{\goth{p}}(\alpha)\ge0$ for all other $\goth{p}$. + + The argument $x$ may also be given as a prime ideal factorization, as + output by \kbd{idealfactor}, but allowing zero exponents. + This yields an element $\alpha$ such that for all prime ideals $\goth{p}$ + occurring in $x$, $v_{\goth{p}}(\alpha) = v_{\goth{p}}(x)$; + for all other prime ideals, $v_{\goth{p}}(\alpha)\ge0$. + + $\fl$ is deprecated (ignored), kept for backward compatibility. +Variant: Use directly \fun{GEN}{idealappr}{GEN nf, GEN x} since $\fl$ is ignored. + +Function: idealchinese +Class: basic +Section: number_fields +C-Name: idealchinese +Prototype: GGDG +Help: idealchinese(nf,x,{y}): x being a prime ideal factorization and y a + vector of elements, gives an element b such that v_p(b-y_p)>=v_p(x) for all + prime ideals p dividing x, and v_p(b)>=0 for all other p. If y is omitted, + return a data structure which can be used in place of x in later calls. +Doc: $x$ being a prime ideal factorization (i.e.~a 2-columns matrix whose first + column contains prime ideals and the second column contains integral + exponents), $y$ a vector of elements in $\var{nf}$ indexed by the ideals in + $x$, computes an element $b$ such that + + $v_{\goth{p}}(b - y_{\goth{p}}) \geq v_{\goth{p}}(x)$ for all prime ideals + in $x$ and $v_{\goth{p}}(b)\geq 0$ for all other $\goth{p}$. + + \bprog + ? K = nfinit(t^2-2); + ? x = idealfactor(K, 2^2*3) + %2 = + [[2, [0, 1]~, 2, 1, [0, 2; 1, 0]] 4] + + [ [3, [3, 0]~, 1, 2, 1] 1] + ? y = [t,1]; + ? idealchinese(K, x, y) + %4 = [4, -3]~ + @eprog + + The argument $x$ may also be of the form $[x, s]$ where the first component + is as above and $s$ is a vector of signs, with $r_{1}$ components + $s_{i}$ in $\{-1,0,1\}$: + if $\sigma_{i}$ denotes the $i$-th real embedding of the number field, + the element $b$ returned satisfies further + $\kbd{sign}(\sigma_{i}(b)) = s_{i}$ for all $i$ such that $s_{i} = \pm1$. + In other words, the sign is fixed to $s_{i}$ at the $i$-th embedding whenever + $s_{i}$ is nonzero. + \bprog + ? idealchinese(K, [x, [1,1]], y) + %5 = [16, -3]~ + ? idealchinese(K, [x, [-1,-1]], y) + %6 = [-20, -3]~ + ? idealchinese(K, [x, [1,-1]], y) + %7 = [4, -3]~ + @eprog + + If $y$ is omitted, return a data structure which can be used in + place of $x$ in later calls and allows to solve many chinese remainder + problems for a given $x$ more efficiently. In this case, the right hand side + $y$ is not allowed to have denominators, unless they are coprime to $x$. + \bprog + ? C = idealchinese(K, [x, [1,1]]); + ? idealchinese(K, C, y) \\ as above + %9 = [16, -3]~ + ? for(i=1,10^4, idealchinese(K,C,y)) \\ ... but faster ! + time = 80 ms. + ? for(i=1,10^4, idealchinese(K,[x,[1,1]],y)) + time = 224 ms. + @eprog + Finally, this structure is itself allowed in place of $x$, the + new $s$ overriding the one already present in the structure. This allows to + initialize for different sign conditions more efficiently when the underlying + ideal factorization remains the same. + \bprog + ? D = idealchinese(K, [C, [1,-1]]); \\ replaces [1,1] + ? idealchinese(K, D, y) + %13 = [4, -3]~ + ? for(i=1,10^4,idealchinese(K,[C,[1,-1]])) + time = 40 ms. \\ faster than starting from scratch + ? for(i=1,10^4,idealchinese(K,[x,[1,-1]])) + time = 128 ms. + @eprog +Variant: Also available is + \fun{GEN}{idealchineseinit}{GEN nf, GEN x} when $y = \kbd{NULL}$. + +Function: idealcoprime +Class: basic +Section: number_fields +C-Name: idealcoprime +Prototype: GGG +Help: idealcoprime(nf,x,y): gives an element b in nf such that b. x is an + integral ideal coprime to the integral ideal y. +Doc: given two integral ideals $x$ and $y$ + in the number field $\var{nf}$, returns a $\beta$ in the field, + such that $\beta\cdot x$ is an integral ideal coprime to $y$. In fact, + $\beta$ is also guaranteed to be integral outside primes dividing $y$. + +Function: idealdiv +Class: basic +Section: number_fields +C-Name: idealdiv0 +Prototype: GGGD0,L, +Help: idealdiv(nf,x,y,{flag=0}): quotient x/y of two ideals x and y in HNF + in the number field nf. If (optional) flag is nonzero, the quotient is + supposed to be an integral ideal (slightly faster). +Description: + (gen, gen, gen, ?0):gen idealdiv($1, $2, $3) + (gen, gen, gen, 1):gen idealdivexact($1, $2, $3) + (gen, gen, gen, #small):gen $"invalid flag in idealdiv" + (gen, gen, gen, small):gen idealdiv0($1, $2, $3, $4) +Doc: quotient $x\cdot y^{-1}$ of the two ideals $x$ and $y$ in the number + field $\var{nf}$. The result is given in HNF. + + If $\fl$ is nonzero, the quotient $x \cdot y^{-1}$ is assumed to be an + integral ideal. This can be much faster when the norm of the quotient is + small even though the norms of $x$ and $y$ are large. More precisely, + the algorithm cheaply removes all maximal ideals above rational + primes such that $v_{p}(Nx) = v_{p}(Ny)$. +Variant: Also available are \fun{GEN}{idealdiv}{GEN nf, GEN x, GEN y} + ($\fl=0$) and \fun{GEN}{idealdivexact}{GEN nf, GEN x, GEN y} ($\fl=1$). + +Function: idealdown +Class: basic +Section: number_fields +C-Name: idealdown +Prototype: GG +Help: idealdown(nf,x): finds the intersection of the ideal x with Q. +Doc: let $\var{nf}$ be a number field as output by \kbd{nfinit}, and $x$ a + fractional ideal. This function returns the nonnegative rational generator + of $x \cap \Q$. If $x$ is an extended ideal, the extended part is ignored. + \bprog + ? nf = nfinit(y^2+1); + ? idealdown(nf, -1/2) + %2 = 1/2 + ? idealdown(nf, (y+1)/3) + %3 = 2/3 + ? idealdown(nf, [2, 11]~) + %4 = 125 + ? x = idealprimedec(nf, 2)[1]; idealdown(nf, x) + %5 = 2 + ? idealdown(nf, [130, 94; 0, 2]) + %6 = 130 + @eprog + +Function: idealfactor +Class: basic +Section: number_fields +C-Name: gpidealfactor +Prototype: GGDG +Help: idealfactor(nf,x,{lim}): factorization of the ideal x into prime ideals + in the number field nf. If lim is set return partial factorization, using + primes < lim. +Doc: factors into prime ideal powers the ideal $x$ in the number field + $\var{nf}$. The output format is similar to the \kbd{factor} function, and + the prime ideals are represented in the form output by the + \kbd{idealprimedec} function. If \var{lim} is set, return partial + factorization, including only prime ideals above rational primes + $< \var{lim}$. + \bprog + ? nf = nfinit(x^3-2); + ? idealfactor(nf, x) \\ a prime ideal above 2 + %2 = + [[2, [0, 1, 0]~, 3, 1, ...] 1] + + ? A = idealhnf(nf, 6*x, 4+2*x+x^2) + %3 = + [6 0 4] + + [0 6 2] + + [0 0 1] + + ? idealfactor(nf, A) + %4 = + [[2, [0, 1, 0]~, 3, 1, ...] 2] + + [[3, [1, 1, 0]~, 3, 1, ...] 2] + + ? idealfactor(nf, A, 3) \\ restrict to primes above p < 3 + %5 = + [[2, [0, 1, 0]~, 3, 1, ...] 2] + @eprog +Variant: This function should only be used by the \kbd{gp} interface. Use + directly \fun{GEN}{idealfactor}{GEN nf, GEN x} or + \fun{GEN}{idealfactor_limit}{GEN nf, GEN x, ulong lim}. + +Function: idealfactorback +Class: basic +Section: number_fields +C-Name: idealfactorback +Prototype: GGDGD0,L, +Help: idealfactorback(nf,f,{e},{flag = 0}): given a factorization f, gives the + ideal product back. If e is present, f has to be a + vector of the same length, and we return the product of the f[i]^e[i]. If + flag is nonzero, perform idealred along the way. +Doc: gives back the ideal corresponding to a factorization. The integer $1$ + corresponds to the empty factorization. + If $e$ is present, $e$ and $f$ must be vectors of the same length ($e$ being + integral), and the corresponding factorization is the product of the + $f[i]^{e[i]}$. + + If not, and $f$ is vector, it is understood as in the preceding case with $e$ + a vector of 1s: we return the product of the $f[i]$. Finally, $f$ can be a + regular factorization, as produced by \kbd{idealfactor}. + \bprog + ? nf = nfinit(y^2+1); idealfactor(nf, 4 + 2*y) + %1 = + [[2, [1, 1]~, 2, 1, [1, 1]~] 2] + + [[5, [2, 1]~, 1, 1, [-2, 1]~] 1] + + ? idealfactorback(nf, %) + %2 = + [10 4] + + [0 2] + + ? f = %1[,1]; e = %1[,2]; idealfactorback(nf, f, e) + %3 = + [10 4] + + [0 2] + + ? % == idealhnf(nf, 4 + 2*y) + %4 = 1 + @eprog + If $\fl$ is nonzero, perform ideal reductions (\tet{idealred}) along the + way. This is most useful if the ideals involved are all \emph{extended} + ideals (for instance with trivial principal part), so that the principal parts + extracted by \kbd{idealred} are not lost. Here is an example: + \bprog + ? f = vector(#f, i, [f[i], [;]]); \\ transform to extended ideals + ? idealfactorback(nf, f, e, 1) + %6 = [[1, 0; 0, 1], [2, 1; [2, 1]~, 1]] + ? nffactorback(nf, %[2]) + %7 = [4, 2]~ + @eprog + The extended ideal returned in \kbd{\%6} is the trivial ideal $1$, extended + with a principal generator given in factored form. We use \tet{nffactorback} + to recover it in standard form. + +Function: idealfrobenius +Class: basic +Section: number_fields +C-Name: idealfrobenius +Prototype: GGG +Help: idealfrobenius(nf,gal,pr): returns the Frobenius element (pr|nf/Q) + attached to the unramified prime ideal pr in prid format, in the Galois + group gal of the number field nf. +Doc: Let $K$ be the number field defined by $nf$ and assume $K/\Q$ be a + Galois extension with Galois group given \kbd{gal=galoisinit(nf)}, + and that \var{pr} is an unramified prime ideal $\goth{p}$ in \kbd{prid} + format. + This function returns a permutation of \kbd{gal.group} which defines + the Frobenius element $\Frob_{\goth{p}}$ attached to $\goth{p}$. + If $p$ is the unique prime number in $\goth{p}$, then + $\Frob(x)\equiv x^{p}\mod\goth{p}$ for all $x\in\Z_{K}$. + \bprog + ? nf = nfinit(polcyclo(31)); + ? gal = galoisinit(nf); + ? pr = idealprimedec(nf,101)[1]; + ? g = idealfrobenius(nf,gal,pr); + ? galoispermtopol(gal,g) + %5 = x^8 + @eprog\noindent This is correct since $101\equiv 8\mod{31}$. + +Function: idealhnf +Class: basic +Section: number_fields +C-Name: idealhnf0 +Prototype: GGDG +Help: idealhnf(nf,u,{v}): hermite normal form of the ideal u in the number + field nf if v is omitted. If called as idealhnf(nf,u,v), the ideal + is given as uZ_K + vZ_K in the number field K defined by nf. +Doc: gives the \idx{Hermite normal form} of the ideal $u\Z_{K}+v\Z_{K}$, + where $u$ and $v$ are elements of the number field $K$ defined by \var{nf}. + \bprog + ? nf = nfinit(y^3 - 2); + ? idealhnf(nf, 2, y+1) + %2 = + [1 0 0] + + [0 1 0] + + [0 0 1] + ? idealhnf(nf, y/2, [0,0,1/3]~) + %3 = + [1/3 0 0] + + [0 1/6 0] + + [0 0 1/6] + @eprog + + If $v$ is omitted, returns the HNF of the ideal defined by $u$: $u$ may be an + algebraic number (defining a principal ideal), a maximal ideal (as given by + \kbd{idealprimedec} or \kbd{idealfactor}), or a matrix whose columns give + generators for the ideal. This last format is a little complicated, but + useful to reduce general modules to the canonical form once in a while: + + \item if strictly less than $N = [K:\Q]$ generators are given, $u$ + is the $\Z_{K}$-module they generate, + + \item if $N$ or more are given, it is \emph{assumed} that they form a + $\Z$-basis of the ideal, in particular that the matrix has maximal rank $N$. + This acts as \kbd{mathnf} since the $\Z_{K}$-module structure is (taken for + granted hence) not taken into account in this case. + \bprog + ? idealhnf(nf, idealprimedec(nf,2)[1]) + %4 = + [2 0 0] + + [0 1 0] + + [0 0 1] + ? idealhnf(nf, [1,2;2,3;3,4]) + %5 = + [1 0 0] + + [0 1 0] + + [0 0 1] + @eprog\noindent Finally, when $K$ is quadratic with discriminant $D_{K}$, we + allow $u =$ \kbd{Qfb(a,b,c)}, provided $b^{2} - 4ac = D_{K}$. As usual, + this represents the ideal $a \Z + (1/2)(-b + \sqrt{D_{K}}) \Z$. + \bprog + ? K = nfinit(x^2 - 60); K.disc + %1 = 60 + ? idealhnf(K, qfbprimeform(60,2)) + %2 = + [2 1] + + [0 1] + ? idealhnf(K, Qfb(1,2,3)) + *** at top-level: idealhnf(K,Qfb(1,2,3 + *** ^-------------------- + *** idealhnf: Qfb(1, 2, 3) has discriminant != 60 in idealhnf. + @eprog +Variant: Also available is \fun{GEN}{idealhnf}{GEN nf, GEN a}, where \kbd{nf} + is a true \var{nf} structure. + +Function: idealintersect +Class: basic +Section: number_fields +C-Name: idealintersect +Prototype: GGG +Help: idealintersect(nf,A,B): intersection of two ideals A and B in the + number field defined by nf. +Doc: intersection of the two ideals + $A$ and $B$ in the number field $\var{nf}$. The result is given in HNF. + \bprog + ? nf = nfinit(x^2+1); + ? idealintersect(nf, 2, x+1) + %2 = + [2 0] + + [0 2] + @eprog + + This function does not apply to general $\Z$-modules, e.g.~orders, since its + arguments are replaced by the ideals they generate. The following script + intersects $\Z$-modules $A$ and $B$ given by matrices of compatible + dimensions with integer coefficients: + \bprog + ZM_intersect(A,B) = + { my(Ker = matkerint(concat(A,B))); + mathnf( A * Ker[1..#A,] ) + } + @eprog + +Function: idealinv +Class: basic +Section: number_fields +C-Name: idealinv +Prototype: GG +Help: idealinv(nf,x): inverse of the ideal x in the number field nf. +Description: + (gen, gen):gen idealinv($1, $2) +Doc: inverse of the ideal $x$ in the + number field $\var{nf}$, given in HNF. If $x$ is an extended + ideal\sidx{ideal (extended)}, its principal part is suitably + updated: i.e. inverting $[I,t]$, yields $[I^{-1}, 1/t]$. + +Function: idealismaximal +Class: basic +Section: number_fields +C-Name: idealismaximal +Prototype: GG +Help: idealismaximal(nf,x): if x is a maximal ideal, return it in prid form, + else return 0. +Doc: given \var{nf} a number field as output by \kbd{nfinit} and an ideal + $x$, return $0$ if $x$ is not a maximal ideal. Otherwise return a \kbd{prid} + structure \var{nf} attached to the ideal. This function uses + \kbd{ispseudoprime} and may return a wrong result in case the underlying + rational pseudoprime is not an actual prime number: apply \kbd{isprime(pr.p)} + to guarantee correctness. If $x$ is an extended ideal, the extended part is + ignored. + \bprog + ? K = nfinit(y^2 + 1); + ? idealismaximal(K, 3) \\ 3 is inert + %2 = [3, [3, 0]~, 1, 2, 1] + ? idealismaximal(K, 5) \\ 5 is not + %3 = 0 + ? pr = idealprimedec(K,5)[1] \\ already a prid + %4 = [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] + ? idealismaximal(K, pr) \\ trivial check + %5 = [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] + ? x = idealhnf(K, pr) + %6 = + [5 3] + + [0 1] + ? idealismaximal(K, x) \\ converts from matrix form to prid + %7 = [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] + @eprog\noindent This function is noticeably faster than \kbd{idealfactor} + since it never involves an actually factorization, in particular when $x + \cap \Z$ is not a prime number. + +Function: idealispower +Class: basic +Section: number_fields +C-Name: idealispower +Prototype: lGGLD& +Help: idealispower(nf,A,n,{&B}): return 1 if A = B^n is an n-th power + else return 0. +Doc: let \var{nf} be a number field and $n > 0$ be a positive integer. + Return $1$ if the fractional ideal $A = B^{n}$ is an $n$-th power and $0$ + otherwise. If the argument $B$ is present, set it to the $n$-th root of $A$, + in HNF. + \bprog + ? K = nfinit(x^3 - 2); + ? A = [46875, 30966, 9573; 0, 3, 0; 0, 0, 3]; + ? idealispower(K, A, 3, &B) + %3 = 1 + ? B + %4 = + [75 22 41] + + [ 0 1 0] + + [ 0 0 1] + + ? A = [9375, 2841, 198; 0, 3, 0; 0, 0, 3]; + ? idealispower(K, A, 3) + %5 = 0 + @eprog\noindent + +Function: ideallist +Class: basic +Section: number_fields +C-Name: gideallist +Prototype: GGD4,L, +Help: ideallist(nf,bound,{flag=4}): vector of vectors L of all idealstar of + all ideals of norm<=bound. If (optional) flag is present, its binary digits + are toggles meaning 1: give generators; 2: add units; 4: give only the + ideals and not the bid; 8: omit ideals which cannot be conductors. +Doc: computes the list of all ideals of norm less or equal to \var{bound} in + the number field + \var{nf}. The result is a row vector with exactly \var{bound} components. + Each component is itself a row vector containing the information about + ideals of a given norm, in no specific order. The information is inferred + from local data and Chinese remainders and less expensive than computing + than a direct global computation. + + The binary digits of $\fl$ mean: + + \item 1: if the ideals are given by a \var{bid}, include generators; + otherwise don't. + + \item 2: if this bit is set, \var{nf} must be a \var{bnf} with units. Each + component is of the form $[\var{bid},U]$, where \var{bid} is attached to + an ideal $f$ and $U$ is a vector of discrete logarithms of the units in + $(\Z_{K}/f)^{*}$. More precisely, $U$ gives the \kbd{ideallog}s with respect + to \var{bid} of $(\zeta,u_{1},\dots,u_{r})$ + where $\zeta$ is the torsion unit generator \kbd{bnf.tu[2]} and $(u_{i})$ + are the fundamental units in \kbd{bnf.fu}. + This structure is technical, meant to be used in conjunction with + \tet{bnrclassnolist} or \tet{bnrdisclist}. + + \item 4: give only the ideal (in HNF), else a \var{bid}. + + \item 8: omit ideals which cannot be conductors, i.e. divisible exactly by + a prime ideal of norm $2$. + + \bprog + ? nf = nfinit(x^2+1); + ? L = ideallist(nf, 100); + ? L[1] + %3 = [[1, 0; 0, 1]] \\@com A single ideal of norm 1 + ? #L[65] + %4 = 4 \\@com There are 4 ideals of norm 65 in $\Z[i]$ + @eprog + If one wants more information: + \bprog + ? L = ideallist(nf, 100, 0); + ? l = L[25]; vector(#l, i, l[i].clgp) + %6 = [[20, [20]], [16, [4, 4]], [20, [20]]] + ? l[1].mod + %7 = [[25, 18; 0, 1], []] + ? l[2].mod + %8 = [[5, 0; 0, 5], []] + ? l[3].mod + %9 = [[25, 7; 0, 1], []] + @eprog\noindent where we ask for the structures of the $(\Z[i]/f)^{*}$ for all + three ideals of norm $25$. In fact, for all moduli with finite part of norm + $25$ and trivial Archimedean part, as the last 3 commands show. See + \tet{ideallistarch} to treat general moduli. + + Finally, one can input a negative \kbd{bound}. The function + then returns the ideals of norm $|\kbd{bound}|$, given by their + factorization matrix. The only valid value of \fl\ is then the default. + If needed, one can obtain their HNF using + \kbd{idealfactorback}, and the corresponding \var{bid} structures using + \kbd{idealstar} (which accepts ideals in factored form). +Variant: Also available is + \fun{GEN}{ideallist0}{GEN nf,long bound, long flag} for a non-negative + bound. + +Function: ideallistarch +Class: basic +Section: number_fields +C-Name: ideallistarch +Prototype: GGG +Help: ideallistarch(nf,list,arch): list is a vector of vectors of bid's as + output by ideallist. Return a vector of vectors with the same number of + components as the original list. The leaves give information about + moduli whose finite part is as in original list, in the same order, and + Archimedean part is now arch. The information contained is of the same kind + as was present in the input. +Doc: + \var{list} is a vector of vectors of bid's, as output by \tet{ideallist} with + flag $0$ to $3$. Return a vector of vectors with the same number of + components as the original \var{list}. The leaves give information about + moduli whose finite part is as in original list, in the same order, and + Archimedean part is now \var{arch} (it was originally trivial). The + information contained is of the same kind as was present in the input; see + \tet{ideallist}, in particular the meaning of \fl. + + \bprog + ? bnf = bnfinit(x^2-2); + ? bnf.sign + %2 = [2, 0] \\@com two places at infinity + ? L = ideallist(bnf, 100, 0); + ? l = L[98]; vector(#l, i, l[i].clgp) + %4 = [[42, [42]], [36, [6, 6]], [42, [42]]] + ? La = ideallistarch(bnf, L, [1,1]); \\@com add them to the modulus + ? l = La[98]; vector(#l, i, l[i].clgp) + %6 = [[168, [42, 2, 2]], [144, [6, 6, 2, 2]], [168, [42, 2, 2]]] + @eprog + Of course, the results above are obvious: adding $t$ places at infinity will + add $t$ copies of $\Z/2\Z$ to $(\Z_{K}/f)^{*}$. The following application + is more typical: + \bprog + ? L = ideallist(bnf, 100, 2); \\@com units are required now + ? La = ideallistarch(bnf, L, [1,1]); + ? H = bnrclassnolist(bnf, La); + ? H[98]; + %4 = [2, 12, 2] + @eprog + +Function: ideallog +Class: basic +Section: number_fields +C-Name: ideallog +Prototype: DGGG +Help: ideallog({nf},x,bid): if bid is a big ideal, as given by + idealstar(nf,D,...), gives the vector of exponents on the generators bid.gen + (even if these generators have not been explicitly computed). +Doc: $\var{nf}$ is a number field, + \var{bid} is as output by \kbd{idealstar(nf, D, \dots)} and $x$ an + element of \var{nf} which must have valuation + equal to 0 at all prime ideals in the support of $\kbd{D}$ and need not be + integral. This function + computes the discrete logarithm of $x$ on the generators given in + \kbd{\var{bid}.gen}. In other words, if $g_{i}$ are these generators, of orders + $d_{i}$ respectively, the result is a column vector of integers $(x_{i})$ such + that $0\le x_{i}1$). + + The components of \kbd{pr} should be accessed by member functions: \kbd{pr.p}, + \kbd{pr.e}, \kbd{pr.f}, and \kbd{pr.gen} (returns the vector $[p,a]$): + \bprog + ? K = nfinit(x^3-2); + ? P = idealprimedec(K, 5); + ? #P \\ 2 primes above 5 in Q(2^(1/3)) + %3 = 2 + ? [p1,p2] = P; + ? [p1.e, p1.f] \\ the first is unramified of degree 1 + %5 = [1, 1] + ? [p2.e, p2.f] \\ the second is unramified of degree 2 + %6 = [1, 2] + ? p1.gen + %7 = [5, [2, 1, 0]~] + ? nfbasistoalg(K, %[2]) \\ a uniformizer for p1 + %8 = Mod(x + 2, x^3 - 2) + ? #idealprimedec(K, 5, 1) \\ restrict to f = 1 + %9 = 1 \\ now only p1 + @eprog + +Function: idealprincipalunits +Class: basic +Section: number_fields +C-Name: idealprincipalunits +Prototype: GGL +Help: idealprincipalunits(nf,pr,k): returns the structure [no, cyc, gen] + of the multiplicative group (1 + pr) / (1 + pr^k). +Doc: given a prime ideal in \tet{idealprimedec} format, + returns the multiplicative group $(1 + \var{pr}) / (1 + \var{pr}^{k})$ as an + abelian group. This function is much faster than \tet{idealstar} when the + norm of \var{pr} is large, since it avoids (useless) work in the + multiplicative group of the residue field. + \bprog + ? K = nfinit(y^2+1); + ? P = idealprimedec(K,2)[1]; + ? G = idealprincipalunits(K, P, 20); + ? G.cyc + %4 = [512, 256, 4] \\ Z/512 x Z/256 x Z/4 + ? G.gen + %5 = [[-1, -2]~, 1021, [0, -1]~] \\ minimal generators of given order + @eprog + +Function: idealramgroups +Class: basic +Section: number_fields +C-Name: idealramgroups +Prototype: GGG +Help: idealramgroups(nf,gal,pr): let pr be a prime ideal in prid format, and + gal the Galois group of the number field nf, return a vector g such that g[1] + is the decomposition group of pr, g[2] is the inertia group, g[i] is the + (i-2)th ramification group of pr, all trivial subgroups being omitted. +Doc: Let $K$ be the number field defined by \var{nf} and assume that $K/\Q$ is + Galois with Galois group $G$ given by \kbd{gal=galoisinit(nf)}. + Let \var{pr} be the prime ideal $\goth{P}$ in prid format. + This function returns a vector $g$ of subgroups of \kbd{gal} + as follows: + + \item \kbd{g[1]} is the decomposition group of $\goth{P}$, + + \item \kbd{g[2]} is $G_{0}(\goth{P})$, the inertia group of $\goth{P}$, + + and for $i\geq 2$, + + \item \kbd{g[i]} is $G_{i-2}(\goth{P})$, the $i-2$-th + \idx{ramification group} of $\goth{P}$. + + \noindent The length of $g$ is the number of nontrivial groups in the + sequence, thus is $0$ if $e=1$ and $f=1$, and $1$ if $f>1$ and $e=1$. + The following function computes the cardinality of a subgroup of $G$, + as given by the components of $g$: + \bprog + card(H) =my(o=H[2]); prod(i=1,#o,o[i]); + @eprog + \bprog + ? nf=nfinit(x^6+3); gal=galoisinit(nf); pr=idealprimedec(nf,3)[1]; + ? g = idealramgroups(nf, gal, pr); + ? apply(card,g) + %3 = [6, 6, 3, 3, 3] \\ cardinalities of the G_i + @eprog + + \bprog + ? nf=nfinit(x^6+108); gal=galoisinit(nf); pr=idealprimedec(nf,2)[1]; + ? iso=idealramgroups(nf,gal,pr)[2] + %5 = [[Vecsmall([2, 3, 1, 5, 6, 4])], Vecsmall([3])] + ? nfdisc(galoisfixedfield(gal,iso,1)) + %6 = -3 + @eprog\noindent The field fixed by the inertia group of $2$ is not ramified at + $2$. + +Function: idealred +Class: basic +Section: number_fields +C-Name: idealred0 +Prototype: GGDG +Help: idealred(nf,I,{v=0}): LLL reduction of the ideal I in the number + field nf along direction v, in HNF. +Doc: \idx{LLL} reduction of + the ideal $I$ in the number field $K$ attached to \var{nf}, along the + direction $v$. The $v$ parameter is best left omitted, but if it is present, + it must be an $\kbd{nf.r1} + \kbd{nf.r2}$-component vector of + \emph{nonnegative} integers. (What counts is the relative magnitude of the + entries: if all entries are equal, the effect is the same as if the vector + had been omitted.) + + This function finds an $a\in K^{*}$ such that $J = (a)I$ is + ``small'' and integral (see the end for technical details). + The result is the Hermite normal form of + the ``reduced'' ideal $J$. + \bprog + ? K = nfinit(y^2+1); + ? P = idealprimedec(K,5)[1]; + ? idealred(K, P) + %3 = + [1 0] + + [0 1] + @eprog\noindent More often than not, a \idx{principal ideal} yields the unit + ideal as above. This is a quick and dirty way to check if ideals are principal, + but it is not a necessary condition: a nontrivial result does not prove that + the ideal is nonprincipal. For guaranteed results, see \kbd{bnfisprincipal}, + which requires the computation of a full \kbd{bnf} structure. + + If the input is an extended ideal $[I,s]$, the output is $[J, sa]$; in + this way, one keeps track of the principal ideal part: + \bprog + ? idealred(K, [P, 1]) + %5 = [[1, 0; 0, 1], [2, -1]~] + @eprog\noindent + meaning that $P$ is generated by $[2, -1]~$. The number field element in the + extended part is an algebraic number in any form \emph{or} a factorization + matrix (in terms of number field elements, not ideals!). In the latter case, + elements stay in factored form, which is a convenient way to avoid + coefficient explosion; see also \tet{idealpow}. + + \misctitle{Technical note} The routine computes an LLL-reduced + basis for the lattice $I^{-1}$ equipped with the quadratic + form + $$|| x ||_{v}^{2} = \sum_{i=1}^{r_{1}+r_{2}} + 2^{v_{i}}\varepsilon_{i}|\sigma_{i}(x)|^{2},$$ + where as usual the $\sigma_{i}$ are the (real and) complex embeddings and + $\varepsilon_{i} = 1$, resp.~$2$, for a real, resp.~complex place. The element + $a$ is simply the first vector in the LLL basis. The only reason you may want + to try to change some directions and set some $v_{i}\neq 0$ is to randomize + the elements found for a fixed ideal, which is heuristically useful in index + calculus algorithms like \tet{bnfinit} and \tet{bnfisprincipal}. + + \misctitle{Even more technical note} In fact, the above is a white lie. + We do not use $||\cdot||_{v}$ exactly but a rescaled rounded variant which + gets us faster and simpler LLLs. There's no harm since we are not using any + theoretical property of $a$ after all, except that it belongs to $I^{-1}$ + and that $a I$ is ``expected to be small''. + +Function: idealredmodpower +Class: basic +Section: number_fields +C-Name: idealredmodpower +Prototype: GGUD0,U, +Help: idealredmodpower(nf,x,n,{B=factorlimit}): return b such that x * b^n = v + is small. +Doc: let \var{nf} be a number field, $x$ an ideal in \var{nf} and $n > 0$ be a + positive integer. Return a number field element $b$ such that $x b^{n} = v$ + is small. If $x$ is integral, then $v$ is also integral. + + More precisely, \kbd{idealnumden} reduces the problem to $x$ integral. Then, + factoring out the prime ideals dividing a rational prime $p \leq B$, + we rewrite $x = I J^{n}$ where the ideals $I$ and $J$ are both integral and + $I$ is $B$-smooth. Then we return a small element $b$ in $J^{-1}$. + + The bound $B$ avoids a costly complete factorization of $x$; as soon as the + $n$-core of $x$ is $B$-smooth (i.e., as soon as $I$ is $n$-power free), + then $J$ is as large as possible and so is the expected reduction. + \bprog + ? T = x^6+108; nf = nfinit(T); a = Mod(x,T); + ? setrand(1); u = (2*a^2+a+3)*random(2^1000*x^6)^6; + ? sizebyte(u) + %3 = 4864 + ? b = idealredmodpower(nf,u,2); + ? v2 = nfeltmul(nf,u, nfeltpow(nf,b,2)) + %5 = [34, 47, 15, 35, 9, 3]~ + ? b = idealredmodpower(nf,u,6); + ? v6 = nfeltmul(nf,u, nfeltpow(nf,b,6)) + %7 = [3, 0, 2, 6, -7, 1]~ + @eprog\noindent The last element \kbd{v6}, obtained by reducing + modulo $6$-th powers instead of squares, looks smaller than \kbd{v2} + but its norm is actually a little larger: + \bprog + ? idealnorm(nf,v2) + %8 = 81309 + ? idealnorm(nf,v6) + %9 = 731781 + @eprog + +Function: idealstar +Class: basic +Section: number_fields +C-Name: idealstarmod +Prototype: DGGD1,L,DG +Help: idealstar({nf},N,{flag=1},{cycmod}): gives the structure of (Z_K/N)^*, + where N is + a modulus (an ideal in any form or a vector [f0, foo], where f0 is an ideal + and foo is a {0,1}-vector with r1 components. + If the positive integer cycmod is present, only compute the group + modulo cycmod-th powers. flag is optional, and can be 0: structure as an + abelian group [h,d,g] where h is the order, d the orders of the cyclic + factors and g the generators; if flag=1 (default), gives a bid structure used + in ideallog to compute discrete logarithms; underlying generators are + well-defined but not explicitly computed, which saves time; if flag=2, + same as with flag=1 except that the generators are also given. + If nf is omitted, N must be an integer and we return the structure of (Z/NZ)^*. +Doc: outputs a \kbd{bid} structure, + necessary for computing in the finite abelian group $G = (\Z_{K}/N)^{*}$. Here, + \var{nf} is a number field and $N$ is a \var{modulus}: either an ideal in any + form, or a row vector whose first component is an ideal and whose second + component is a row vector of $r_{1}$ 0 or 1. Ideals can also be given + by a factorization into prime ideals, as produced by \tet{idealfactor}. + + If the positive integer \kbd{cycmod} is present, only compute the group + modulo \kbd{cycmod}-th powers, which may save a lot of time when some + maximal ideals in the modulus have a huge residue field. Whereas you might + only be interested in quadratic or cubic residuosity; see also \kbd{bnrinit} + for applications in class field theory. + + This \var{bid} is used in \tet{ideallog} to compute discrete logarithms. It + also contains useful information which can be conveniently retrieved as + \kbd{\var{bid}.mod} (the modulus), + \kbd{\var{bid}.clgp} ($G$ as a finite abelian group), + \kbd{\var{bid}.no} (the cardinality of $G$), + \kbd{\var{bid}.cyc} (elementary divisors) and + \kbd{\var{bid}.gen} (generators). + + If $\fl=1$ (default), the result is a \kbd{bid} structure without + generators: they are well defined but not explicitly computed, which saves + time. + + If $\fl=2$, as $\fl=1$, but including generators. + + If $\fl=0$, only outputs $(\Z_{K}/N)^{*}$ as an abelian group, + i.e as a 3-component vector $[h,d,g]$: $h$ is the order, $d$ is the vector of + SNF\sidx{Smith normal form} cyclic components and $g$ the corresponding + generators. + + If \var{nf} is omitted, we take it to be the rational number fields, $N$ must + be an integer and we return the structure of $(\Z/N\Z)^{*}$. In other words + \kbd{idealstar(, N, flag)} is short for + \bprog + idealstar(nfinit(x), N, flag) + @eprog\noindent but faster. The alternative syntax \kbd{znstar(N, flag)} + is also available for an analogous effect but, due to an unfortunate + historical oversight, the default value of $\fl$ is different in + the two functions (\kbd{znstar} does not initialize by default, you probably + want \kbd{znstar(N,1)}). +Variant: Instead the above hardcoded numerical flags, one should rather use + \fun{GEN}{Idealstarmod}{GEN nf, GEN ideal, long flag, GEN cycmod} or + \fun{GEN}{Idealstar}{GEN nf, GEN ideal, long flag} (\kbd{cycmod} is + \kbd{NULL}), where $\fl$ is + an or-ed combination of \tet{nf_GEN} (include generators) and \tet{nf_INIT} + (return a full \kbd{bid}, not a group), possibly $0$. This offers + one more combination: gen, but no init. The \kbd{nf} argument must be a true + \var{nf} structure. + +Function: idealtwoelt +Class: basic +Section: number_fields +C-Name: idealtwoelt0 +Prototype: GGDG +Help: idealtwoelt(nf,x,{a}): two-element representation of an ideal x in the + number field nf. If (optional) a is nonzero, first element will be equal to a. +Doc: computes a two-element representation of the ideal $x$ in the number + field $\var{nf}$, combining a random search and an approximation theorem; $x$ + is an ideal in any form (possibly an extended ideal, whose principal part is + ignored) + + \item When called as \kbd{idealtwoelt(nf,x)}, the result is a row vector + $[a,\alpha]$ with two components such that $x=a\Z_{K}+\alpha\Z_{K}$ and $a$ is + chosen to be the positive generator of $x\cap\Z$, unless $x$ was given as a + principal ideal in which case we may choose $a = 0$. The algorithm + uses a fast lazy factorization of $x\cap \Z$ and runs in randomized + polynomial time. + + \bprog + ? K = nfinit(t^5-23); + ? x = idealhnf(K, t^2*(t+1), t^3*(t+1)) + %2 = \\ some random ideal of norm 552*23 + [552 23 23 529 23] + + [ 0 23 0 0 0] + + [ 0 0 1 0 0] + + [ 0 0 0 1 0] + + [ 0 0 0 0 1] + + ? [a,alpha] = idealtwoelt(K, x) + %3 = [552, [23, 0, 1, 0, 0]~] + ? nfbasistoalg(K, alpha) + %4 = Mod(t^2 + 23, t^5 - 23) + @eprog + + \item When called as \kbd{idealtwoelt(nf,x,a)} with an explicit nonzero $a$ + supplied as third argument, the function assumes that $a \in x$ and returns + $\alpha\in x$ such that $x = a\Z_{K} + \alpha\Z_{K}$. Note that we must factor + $a$ in this case, and the algorithm is generally slower than the + default variant and gives larger generators: + \bprog + ? alpha2 = idealtwoelt(K, x, 552) + %5 = [-161, -161, -183, -207, 0]~ + ? idealhnf(K, 552, alpha2) == x + %6 = 1 + @eprog\noindent Note that, in both cases, the return value is \emph{not} + recognized as an ideal by GP functions; one must use \kbd{idealhnf} as + above to recover a valid ideal structure from the two-element representation. +Variant: Also available are + \fun{GEN}{idealtwoelt}{GEN nf, GEN x} and + \fun{GEN}{idealtwoelt2}{GEN nf, GEN x, GEN a}. + +Function: idealval +Class: basic +Section: number_fields +C-Name: gpidealval +Prototype: GGG +Help: idealval(nf,x,pr): valuation at pr given in idealprimedec format of the + ideal x in the number field nf. +Doc: gives the valuation of the ideal $x$ at the prime ideal \var{pr} in the + number field $\var{nf}$, where \var{pr} is in \kbd{idealprimedec} format. + The valuation of the $0$ ideal is \kbd{+oo}. +Variant: Also available is + \fun{long}{idealval}{GEN nf, GEN x, GEN pr}, which returns + \tet{LONG_MAX} if $x = 0$ and the valuation as a \kbd{long} integer. + +Function: if +Class: basic +Section: programming/control +C-Name: ifpari +Prototype: GDEDE +Help: if(a,{seq1},{seq2}): if a is nonzero, seq1 is evaluated, otherwise seq2. + seq1 and seq2 are optional, and if seq2 is omitted, the preceding comma can + be omitted also. +Doc: evaluates the expression sequence \var{seq1} if $a$ is nonzero, otherwise + the expression \var{seq2}. Of course, \var{seq1} or \var{seq2} may be empty: + + \kbd{if ($a$,\var{seq})} evaluates \var{seq} if $a$ is not equal to zero + (you don't have to write the second comma), and does nothing otherwise, + + \kbd{if ($a$,,\var{seq})} evaluates \var{seq} if $a$ is equal to zero, and + does nothing otherwise. You could get the same result using the \kbd{!} + (\kbd{not}) operator: \kbd{if (!$a$,\var{seq})}. + + The value of an \kbd{if} statement is the value of the branch that gets + evaluated: for instance + \bprog + x = if(n % 4 == 1, y, z); + @eprog\noindent sets $x$ to $y$ if $n$ is $1$ modulo $4$, and to $z$ + otherwise. + + Successive 'else' blocks can be abbreviated in a single compound \kbd{if} + as follows: + \bprog + if (test1, seq1, + test2, seq2, + ... + testn, seqn, + seqdefault); + @eprog\noindent is equivalent to + \bprog + if (test1, seq1 + , if (test2, seq2 + , ... + if (testn, seqn, seqdefault)...)); + @eprog For instance, this allows to write traditional switch / case + constructions: + \bprog + if (x == 0, do0(), + x == 1, do1(), + x == 2, do2(), + dodefault()); + @eprog + + \misctitle{Remark} + The boolean operators \kbd{\&\&} and \kbd{||} are evaluated + according to operator precedence as explained in \secref{se:operators}, but, + contrary to other operators, the evaluation of the arguments is stopped + as soon as the final truth value has been determined. For instance + \bprog + if (x != 0 && f(1/x), ...) + @eprog + \noindent is a perfectly safe statement. + + \misctitle{Remark} Functions such as \kbd{break} and \kbd{next} operate on + \emph{loops}, such as \kbd{for$xxx$}, \kbd{while}, \kbd{until}. The \kbd{if} + statement is \emph{not} a loop. (Obviously!) + +Function: iferr +Class: basic +Section: programming/control +C-Name: iferrpari +Prototype: EVEDE +Help: iferr(seq1,E,seq2,{pred}): evaluates the expression sequence seq1. If + an error occurs, set the formal parameter E set to the error data. + If pred is not present or evaluates to true, catch the error and evaluate + seq2. Both pred and seq2 can reference E. +Doc: evaluates the expression sequence \var{seq1}. If an error occurs, + set the formal parameter \var{E} set to the error data. + If \var{pred} is not present or evaluates to true, catch the error + and evaluate \var{seq2}. Both \var{pred} and \var{seq2} can reference \var{E}. + The error type is given by \kbd{errname(E)}, and other data can be + accessed using the \tet{component} function. The code \var{seq2} should check + whether the error is the one expected. In the negative the error can be + rethrown using \tet{error(E)} (and possibly caught by an higher \kbd{iferr} + instance). The following uses \kbd{iferr} to implement Lenstra's ECM factoring + method + \bprog + ? ecm(N, B = 1000!, nb = 100)= + { + for(a = 1, nb, + iferr(ellmul(ellinit([a,1]*Mod(1,N)), [0,1]*Mod(1,N), B), + E, return(gcd(lift(component(E,2)),N)), + errname(E)=="e_INV" && type(component(E,2)) == "t_INTMOD")) + } + ? ecm(2^101-1) + %2 = 7432339208719 + @eprog + The return value of \kbd{iferr} itself is the value of \var{seq2} if an + error occurs, and the value of \var{seq1} otherwise. We now describe the + list of valid error types, and the attached error data \var{E}; in each + case, we list in order the components of \var{E}, accessed via + \kbd{component(E,1)}, \kbd{component(E,2)}, etc. + + \misctitle{Internal errors, ``system'' errors} + + \item \kbd{"e\_ARCH"}. A requested feature $s$ is not available on this + architecture or operating system. + \var{E} has one component (\typ{STR}): the missing feature name $s$. + + \item \kbd{"e\_BUG"}. A bug in the PARI library, in function $s$. + \var{E} has one component (\typ{STR}): the function name $s$. + + \item \kbd{"e\_FILE"}. Error while trying to open a file. + \var{E} has two components, 1 (\typ{STR}): the file type (input, output, + etc.), 2 (\typ{STR}): the file name. + + \item \kbd{"e\_IMPL"}. A requested feature $s$ is not implemented. + \var{E} has one component, 1 (\typ{STR}): the feature name $s$. + + \item \kbd{"e\_PACKAGE"}. Missing optional package $s$. + \var{E} has one component, 1 (\typ{STR}): the package name $s$. + + \misctitle{Syntax errors, type errors} + + \item \kbd{"e\_DIM"}. The dimensions of arguments $x$ and $y$ submitted + to function $s$ does not match up. + E.g., multiplying matrices of inconsistent dimension, adding vectors of + different lengths,\dots + \var{E} has three component, 1 (\typ{STR}): the function name $s$, 2: the + argument $x$, 3: the argument $y$. + + \item \kbd{"e\_FLAG"}. A flag argument is out of bounds in function $s$. + \var{E} has one component, 1 (\typ{STR}): the function name $s$. + + \item \kbd{"e\_NOTFUNC"}. Generated by the PARI evaluator; tried to use a + \kbd{GEN} $x$ which is not a \typ{CLOSURE} in a function call syntax (as in + \kbd{f = 1; f(2);}). + \var{E} has one component, 1: the offending \kbd{GEN} $x$. + + \item \kbd{"e\_OP"}. Impossible operation between two objects than cannot + be typecast to a sensible common domain for deeper reasons than a type + mismatch, usually for arithmetic reasons. As in \kbd{O(2) + O(3)}: it is + valid to add two \typ{PADIC}s, provided the underlying prime is the same; so + the addition is not forbidden a priori for type reasons, it only becomes so + when inspecting the objects and trying to perform the operation. + \var{E} has three components, 1 (\typ{STR}): the operator name \var{op}, + 2: first argument, 3: second argument. + + \item \kbd{"e\_TYPE"}. An argument $x$ of function $s$ had an unexpected type. + (As in \kbd{factor("blah")}.) + \var{E} has two components, 1 (\typ{STR}): the function name $s$, + 2: the offending argument $x$. + + \item \kbd{"e\_TYPE2"}. Forbidden operation between two objects than cannot be + typecast to a sensible common domain, because their types do not match up. + (As in \kbd{Mod(1,2) + Pi}.) + \var{E} has three components, 1 (\typ{STR}): the operator name \var{op}, + 2: first argument, 3: second argument. + + \item \kbd{"e\_PRIORITY"}. Object $o$ in function $s$ contains + variables whose priority is incompatible with the expected operation. + E.g.~\kbd{Pol([x,1], 'y)}: this raises an error because it's not possible to + create a polynomial whose coefficients involve variables with higher priority + than the main variable. $E$ has four components: 1 (\typ{STR}): the function + name $s$, 2: the offending argument $o$, 3 (\typ{STR}): an operator + $\var{op}$ describing the priority error, 4 (\typ{POL}): + the variable $v$ describing the priority error. The argument + satisfies $\kbd{variable}(x)~\var{op} \kbd{variable}(v)$. + + \item \kbd{"e\_VAR"}. The variables of arguments $x$ and $y$ submitted + to function $s$ does not match up. E.g., considering the algebraic number + \kbd{Mod(t,t\pow2+1)} in \kbd{nfinit(x\pow2+1)}. + \var{E} has three component, 1 (\typ{STR}): the function name $s$, 2 + (\typ{POL}): the argument $x$, 3 (\typ{POL}): the argument $y$. + + \misctitle{Overflows} + + \item \kbd{"e\_COMPONENT"}. Trying to access an inexistent component in a + vector/matrix/list in a function: the index is less than $1$ or greater + than the allowed length. + \var{E} has four components, + 1 (\typ{STR}): the function name + 2 (\typ{STR}): an operator $\var{op}$ ($<$ or $>$), + 2 (\typ{GEN}): a numerical limit $l$ bounding the allowed range, + 3 (\kbd{GEN}): the index $x$. It satisfies $x$ \var{op} $l$. + + \item \kbd{"e\_DOMAIN"}. An argument is not in the function's domain. + \var{E} has five components, 1 (\typ{STR}): the function name, + 2 (\typ{STR}): the mathematical name of the out-of-domain argument + 3 (\typ{STR}): an operator $\var{op}$ describing the domain error, + 4 (\typ{GEN}): the numerical limit $l$ describing the domain error, + 5 (\kbd{GEN}): the out-of-domain argument $x$. The argument satisfies $x$ + \var{op} $l$, which prevents it from belonging to the function's domain. + + \item \kbd{"e\_MAXPRIME"}. A function using the precomputed list of prime + numbers ran out of primes. + \var{E} has one component, 1 (\typ{INT}): the requested prime bound, which + overflowed \kbd{primelimit} or $0$ (bound is unknown). + + \item \kbd{"e\_MEM"}. A call to \tet{pari_malloc} or \tet{pari_realloc} + failed. \var{E} has no component. + + \item \kbd{"e\_OVERFLOW"}. An object in function $s$ becomes too large to be + represented within PARI's hardcoded limits. (As in \kbd{2\pow2\pow2\pow10} or + \kbd{exp(1e100)}, which overflow in \kbd{lg} and \kbd{expo}.) + \var{E} has one component, 1 (\typ{STR}): the function name $s$. + + \item \kbd{"e\_PREC"}. Function $s$ fails because input accuracy is too low. + (As in \kbd{floor(1e100)} at default accuracy.) + \var{E} has one component, 1 (\typ{STR}): the function name $s$. + + \item \kbd{"e\_STACK"}. The PARI stack overflows. + \var{E} has no component. + + \misctitle{Errors triggered intentionally} + + \item \kbd{"e\_ALARM"}. A timeout, generated by the \tet{alarm} function. + \var{E} has one component (\typ{STR}): the error message to print. + + \item \kbd{"e\_USER"}. A user error, as triggered by + \tet{error}($g_{1},\dots,g_{n})$. + \var{E} has one component, 1 (\typ{VEC}): the vector of $n$ arguments given + to \kbd{error}. + + \misctitle{Mathematical errors} + + \item \kbd{"e\_CONSTPOL"}. An argument of function $s$ is a constant + polynomial, which does not make sense. (As in \kbd{galoisinit(Pol(1))}.) + \var{E} has one component, 1 (\typ{STR}): the function name $s$. + + \item \kbd{"e\_COPRIME"}. Function $s$ expected coprime arguments, + and did receive $x,y$, which were not. + \var{E} has three component, 1 (\typ{STR}): the function name $s$, + 2: the argument $x$, 3: the argument $y$. + + \item \kbd{"e\_INV"}. Tried to invert a noninvertible object $x$ in + function $s$. + \var{E} has two components, 1 (\typ{STR}): the function name $s$, + 2: the noninvertible $x$. If $x = \kbd{Mod}(a,b)$ + is a \typ{INTMOD} and $a$ is not $0$ mod $b$, this allows to factor + the modulus, as \kbd{gcd}$(a,b)$ is a nontrivial divisor of $b$. + + \item \kbd{"e\_IRREDPOL"}. Function $s$ expected an irreducible polynomial, + and did receive $T$, which was not. (As in \kbd{nfinit(x\pow2-1)}.) + \var{E} has two component, 1 (\typ{STR}): the function name $s$, + 2 (\typ{POL}): the polynomial $x$. + + \item \kbd{"e\_MISC"}. Generic uncategorized error. + \var{E} has one component (\typ{STR}): the error message to print. + + \item \kbd{"e\_MODULUS"}. moduli $x$ and $y$ submitted to function $s$ are + inconsistent. As in + \bprog + nfalgtobasis(nfinit(t^3-2), Mod(t,t^2+1)) + @eprog\noindent + \var{E} has three component, 1 (\typ{STR}): the function $s$, + 2: the argument $x$, 3: the argument $y$. + + \item \kbd{"e\_PRIME"}. Function $s$ expected a prime number, + and did receive $p$, which was not. (As in \kbd{idealprimedec(nf, 4)}.) + \var{E} has two component, 1 (\typ{STR}): the function name $s$, + 2: the argument $p$. + + \item \kbd{"e\_ROOTS0"}. An argument of function $s$ is a zero polynomial, + and we need to consider its roots. (As in \kbd{polroots(0)}.) \var{E} has + one component, 1 (\typ{STR}): the function name $s$. + + \item \kbd{"e\_SQRTN"}. Trying to compute an $n$-th root of $x$, which does + not exist, in function $s$. (As in \kbd{sqrt(Mod(-1,3))}.) + \var{E} has two components, 1 (\typ{STR}): the function name $s$, + 2: the argument $x$. + +Function: imag +Class: basic +Section: conversions +C-Name: gimag +Prototype: G +Help: imag(x): imaginary part of x. +Doc: imaginary part of $x$. When $x$ is a quadratic number, this is the + coefficient of $\omega$ in the ``canonical'' integral basis $(1,\omega)$. + \bprog + ? imag(3 + I) + %1 = 1 + ? x = 3 + quadgen(-23); + ? imag(x) \\ as a quadratic number + %3 = 1 + ? imag(x * 1.) \\ as a complex number + %4 = 2.3979157616563597707987190320813469600 + @eprog + +Function: incgam +Class: basic +Section: transcendental +C-Name: incgam0 +Prototype: GGDGp +Help: incgam(s,x,{g}): incomplete gamma function. g is optional and is the + precomputed value of gamma(s). +Doc: incomplete gamma function $\int_{x}^{\infty} e^{-t}t^{s-1}\,dt$, + extended by + analytic continuation to all complex $x, s$ not both $0$. The relative error + is bounded in terms of the precision of $s$ (the accuracy of $x$ is ignored + when determining the output precision). When $g$ is given, assume that + $g=\Gamma(s)$. For small $|x|$, this will speed up the computation. +Variant: Also available is \fun{GEN}{incgam}{GEN s, GEN x, long prec}. + +Function: incgamc +Class: basic +Section: transcendental +C-Name: incgamc +Prototype: GGp +Help: incgamc(s,x): complementary incomplete gamma function. +Doc: complementary incomplete gamma function. + The arguments $x$ and $s$ are complex numbers such that $s$ is not a pole of + $\Gamma$ and $|x|/(|s|+1)$ is not much larger than 1 (otherwise the + convergence is very slow). The result returned is $\int_{0}^{x} + e^{-t}t^{s-1}\,dt$. + +Function: inline +Class: basic +Section: programming/specific +Obsolete: 2018-11-27 +Help: inline(x,...,z): declares x,...,z as inline variables. DEPRECATED, use + export. +Doc: declare $x,\ldots, z$ as inline variables. Such variables + behave like lexically scoped variable (see my()) but with unlimited scope. + It is however possible to exit the scope by using \kbd{uninline()}. + When used in a GP script, it is recommended to call \kbd{uninline()} before + the script's end to avoid inline variables leaking outside the script. + DEPRECATED, use \kbd{export}. + +Function: input +Class: basic +Section: programming/specific +C-Name: gp_input +Prototype: +Help: input(): read an expression from the input file or standard input. +Doc: reads a string, interpreted as a GP expression, + from the input file, usually standard input (i.e.~the keyboard). If a + sequence of expressions is given, the result is the result of the last + expression of the sequence. When using this instruction, it is useful to + prompt for the string by using the \kbd{print1} function. Note that in the + present version 2.19 of \kbd{pari.el}, when using \kbd{gp} under GNU Emacs (see + \secref{se:emacs}) one \emph{must} prompt for the string, with a string + which ends with the same prompt as any of the previous ones (a \kbd{"? "} + will do for instance). + +Function: install +Class: basic +Section: programming/specific +C-Name: gpinstall +Prototype: vrrD"",r,D"",s, +Help: install(name,code,{gpname},{lib}): load from dynamic library 'lib' the + function 'name'. Assign to it the name 'gpname' in this GP session, with + prototype 'code'. If 'lib' is omitted, all symbols known to gp + (includes the whole 'libpari.so' and possibly others) are available. + If 'gpname' is omitted, use 'name'. +Doc: loads from dynamic library \var{lib} the function \var{name}. Assigns to it + the name \var{gpname} in this \kbd{gp} session, with \emph{prototype} + \var{code} (see below). If \var{gpname} is omitted, uses \var{name}. + If \var{lib} is omitted, all symbols known to \kbd{gp} are available: this + includes the whole of \kbd{libpari.so} and possibly others (such as + \kbd{libc.so}). + + Most importantly, \kbd{install} gives you access to all nonstatic functions + defined in the PARI library. For instance, the function + \bprog + GEN addii(GEN x, GEN y) + @eprog\noindent adds two PARI integers, and is not directly accessible under + \kbd{gp} (it is eventually called by the \kbd{+} operator of course): + \bprog + ? install("addii", "GG") + ? addii(1, 2) + %1 = 3 + @eprog\noindent + It also allows to add external functions to the \kbd{gp} interpreter. + For instance, it makes the function \tet{system} obsolete: + \bprog + ? install(system, vs, sys,/*omitted*/) + ? sys("ls gp*") + gp.c gp.h gp_rl.c + @eprog\noindent This works because \kbd{system} is part of \kbd{libc.so}, + which is linked to \kbd{gp}. It is also possible to compile a shared library + yourself and provide it to gp in this way: use \kbd{gp2c}, or do it manually + (see the \kbd{modules\_build} variable in \kbd{pari.cfg} for hints). + + Re-installing a function will print a warning and update the prototype code + if needed. However, it will not reload a symbol from the library, even if the + latter has been recompiled. + + \misctitle{Prototype} We only give a simplified description here, covering + most functions, but there are many more possibilities. The full documentation + is available in \kbd{libpari.dvi}, see + \bprog + ??prototype + @eprog + + \item First character \kbd{i}, \kbd{l}, \kbd{u}, \kbd{v} : return type + \kbd{int} / \kbd{long} / \kbd{ulong} / \kbd{void}. (Default: \kbd{GEN}) + + \item One letter for each mandatory argument, in the same order as they appear + in the argument list: \kbd{G} (\kbd{GEN}), \kbd{\&} + (\kbd{GEN*}), \kbd{L} (\kbd{long}), \kbd{U} (\kbd{ulong}), + \kbd{s} (\kbd{char *}), \kbd{n} (variable). + + \item \kbd{p} to supply \kbd{realprecision} (usually \kbd{long prec} in the + argument list), \kbd{b} to supply \kbd{realbitprecision} + (usually \kbd{long bitprec}), \kbd{P} to supply \kbd{seriesprecision} + (usually \kbd{long precdl}). + + \noindent We also have special constructs for optional arguments and default + values: + + \item \kbd{DG} (optional \kbd{GEN}, \kbd{NULL} if omitted), + + \item \kbd{D\&} (optional \kbd{GEN*}, \kbd{NULL} if omitted), + + \item \kbd{Dn} (optional variable, $-1$ if omitted), + + For instance the prototype corresponding to + \bprog + long issquareall(GEN x, GEN *n = NULL) + @eprog\noindent is \kbd{lGD\&}. + + \misctitle{Caution} This function may not work on all systems, especially + when \kbd{gp} has been compiled statically. In that case, the first use of an + installed function will provoke a Segmentation Fault (this should never + happen with a dynamically linked executable). If you intend to use this + function, please check first on some harmless example such as the one above + that it works properly on your machine. + +Function: intcirc +Class: basic +Section: sums +C-Name: intcirc0 +Prototype: V=GGEDGp +Help: intcirc(X=a,R,expr,{tab}): numerical integration of expr on the circle + |z-a|=R, divided by 2*I*Pi. tab is as in intnum. +Wrapper: (,,G) +Description: + (gen,gen,gen,?gen):gen:prec intcirc(${3 cookie}, ${3 wrapper}, $1, $2, $4, $prec) +Doc: numerical + integration of $(2i\pi)^{-1}\var{expr}$ with respect to $X$ on the circle + $|X-a| = R$. + In other words, when \var{expr} is a meromorphic + function, sum of the residues in the corresponding disk; \var{tab} is as in + \kbd{intnum}, except that if computed with \kbd{intnuminit} it should be with + the endpoints \kbd{[-1, 1]}. + + \bprog + ? \p105 + ? intcirc(s=1, 0.5, zeta(s)) - 1 + time = 496 ms. + %1 = 1.2883911040127271720 E-101 + 0.E-118*I + @eprog + + \synt{intcirc}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN R,GEN tab, long prec}. + +Function: intformal +Class: basic +Section: polynomials +C-Name: integ +Prototype: GDn +Help: intformal(x,{v}): formal integration of x with respect to v, or to the + main variable of x if v is omitted. +Doc: \idx{formal integration} of $x$ with respect to the variable $v$ (wrt. + the main variable if $v$ is omitted). Since PARI cannot represent + logarithmic or arctangent terms, any such term in the result will yield an + error: + \bprog + ? intformal(x^2) + %1 = 1/3*x^3 + ? intformal(x^2, y) + %2 = y*x^2 + ? intformal(1/x) + *** at top-level: intformal(1/x) + *** ^-------------- + *** intformal: domain error in intformal: residue(series, pole) != 0 + @eprog + The argument $x$ can be of any type. When $x$ is a rational function, we + assume that the base ring is an integral domain of characteristic zero. + + By definition, the main variable of a \typ{POLMOD} is the main variable + among the coefficients from its two polynomial components + (representative and modulus); in other words, assuming a polmod represents an + element of $R[X]/(T(X))$, the variable $X$ is a mute variable and the + integral is taken with respect to the main variable used in the base ring $R$. + In particular, it is meaningless to integrate with respect to the main + variable of \kbd{x.mod}: + \bprog + ? intformal(Mod(1,x^2+1), 'x) + *** intformal: incorrect priority in intformal: variable x = x + @eprog + +Function: intfuncinit +Class: basic +Section: sums +C-Name: intfuncinit0 +Prototype: V=GGED0,L,p +Help: intfuncinit(t=a,b,f,{m=0}): initialize tables for integrations + from a to b using a weight f(t). For integral transforms such + as Fourier or Mellin transforms. +Wrapper: (,,G) +Description: + (gen,gen,gen,?small):gen:prec intfuncinit(${3 cookie}, ${3 wrapper}, $1, $2, $4, $prec) +Doc: initialize tables for use with integral transforms (such as Fourier, + Laplace or Mellin transforms) in order to compute + $$ \int_{a}^{b} f(t) k(t,z) \, dt $$ + for some kernel $k(t,z)$. + The endpoints $a$ and $b$ are coded as in \kbd{intnum}, $f$ is the + function to which the integral transform is to be applied and the + nonnegative integer $m$ is as in \kbd{intnum}: multiply the number of + sampling points roughly by $2^{m}$, hopefully increasing the accuracy. This + function is particularly useful when the function $f$ is hard to compute, + such as a gamma product. + + \misctitle{Limitation} The endpoints $a$ and $b$ must be at infinity, + with the same asymptotic behavior. Oscillating types are not supported. + This is easily overcome by integrating vectors of functions, see example + below. + + \misctitle{Examples} + + \item numerical Fourier transform + $$F(z) = \int_{-\infty}^{+\infty} f(t)e^{-2i\pi z t}\, dt. $$ + First the easy case, assume that $f$ decrease exponentially: + \bprog + f(t) = exp(-t^2); + A = [-oo,1]; + B = [+oo,1]; + \p200 + T = intfuncinit(t = A,B , f(t)); + F(z) = + { my(a = -2*I*Pi*z); + intnum(t = A,B, exp(a*t), T); + } + ? F(1) - sqrt(Pi)*exp(-Pi^2) + %1 = -1.3... E-212 + @eprog\noindent + Now the harder case, $f$ decrease slowly: we must specify the oscillating + behavior. Thus, we cannot precompute usefully since everything depends on + the point we evaluate at: + \bprog + f(t) = 1 / (1+ abs(t)); + \p200 + \\ Fourier cosine transform + FC(z) = + { my(a = 2*Pi*z); + intnum(t = [-oo, a*I], [+oo, a*I], cos(a*t)*f(t)); + } + FC(1) + @eprog + \item Fourier coefficients: we must integrate over a period, but + \kbd{intfuncinit} does not support finite endpoints. + The solution is to integrate a vector of functions ! + \bprog + FourierSin(f, T, k) = \\ first k sine Fourier coeffs + { + my (w = 2*Pi/T); + my (v = vector(k+1)); + intnum(t = -T/2, T/2, + my (z = exp(I*w*t)); + v[1] = z; + for (j = 2, k, v[j] = v[j-1]*z); + f(t) * imag(v)) * 2/T; + } + FourierSin(t->sin(2*t), 2*Pi, 10) + @eprog\noindent The same technique can be used instead of \kbd{intfuncinit} + to integrate $f(t) k(t,z)$ whenever the list of $z$-values is known + beforehand. + + Note that the above code includes an unrelated optimization: the + $\sin(j w t)$ are computed as imaginary parts of $\exp(i j w t)$ and the + latter by successive multiplications. + + \item numerical Mellin inversion + $$F(z) = (2i\pi)^{-1} \int_{c -i\infty}^{c+i\infty} f(s)z^{-s}\, ds + = (2\pi)^{-1} \int_{-\infty}^{+\infty} + f(c + i t)e^{-\log z(c + it)}\, dt. $$ + We take $c = 2$ in the program below: + \bprog + f(s) = gamma(s)^3; \\ f(c+it) decrease as exp(-3Pi|t|/2) + c = 2; \\ arbitrary + A = [-oo,3*Pi/2]; + B = [+oo,3*Pi/2]; + T = intfuncinit(t=A,B, f(c + I*t)); + F(z) = + { my (a = -log(z)); + intnum(t=A,B, exp(a*I*t), T)*exp(a*c) / (2*Pi); + } + @eprog + + \synt{intfuncinit}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b,long m, long prec}. + +Function: intnum +Class: basic +Section: sums +C-Name: intnum0 +Prototype: V=GGEDGp +Help: intnum(X=a,b,expr,{tab}): numerical integration of expr from a to b with + respect to X. Plus/minus infinity is coded as +oo/-oo. Finally tab is + either omitted (let the program choose the integration step), a nonnegative + integer m (divide integration step by 2^m), or data precomputed with + intnuminit. +Wrapper: (,,G) +Description: + (gen,gen,gen,?gen):gen:prec intnum(${3 cookie}, ${3 wrapper}, $1, $2, $4, $prec) +Doc: numerical integration + of \var{expr} on $]a,b[$ with respect to $X$, using the + double-exponential method, and thus $O(D\log D)$ evaluation of + the integrand in precision $D$. The integrand may have values + belonging to a vector space over the real numbers; in particular, it can be + complex-valued or vector-valued. But it is assumed that the function is + regular on $]a,b[$. If the endpoints $a$ and $b$ are finite and the + function is regular there, the situation is simple: + \bprog + ? intnum(x = 0,1, x^2) + %1 = 0.3333333333333333333333333333 + ? intnum(x = 0,Pi/2, [cos(x), sin(x)]) + %2 = [1.000000000000000000000000000, 1.000000000000000000000000000] + @eprog\noindent + An endpoint equal to $\pm\infty$ is coded as \kbd{+oo} or \kbd{-oo}, as + expected: + \bprog + ? intnum(x = 1,+oo, 1/x^2) + %3 = 1.000000000000000000000000000 + @eprog\noindent + In basic usage, it is assumed that the function does not decrease + exponentially fast at infinity: + \bprog + ? intnum(x=0,+oo, exp(-x)) + *** at top-level: intnum(x=0,+oo,exp(- + *** ^-------------------- + *** exp: overflow in expo(). + @eprog\noindent + We shall see in a moment how to avoid that last problem, after describing + the last \emph{optional} argument \var{tab}. + + \misctitle{The \var{tab} argument} The routine uses weights $w_{i}$, which are + mostly independent of the function + being integrated, evaluated at many sampling points $x_{i}$ and + approximates the integral by $\sum w_{i} f(x_{i})$. If \var{tab} is + + \item a nonnegative integer $m$, we multiply the number of sampling points + by $2^{m}$, hopefully increasing accuracy. Note that the running time + increases roughly by a factor $2^{m}$. One may try consecutive values of $m$ + until they give the same value up to an accepted error. + + \item a set of integration tables containing precomputed $x_{i}$ and $w_{i}$ + as output by \tet{intnuminit}. This is useful if several integrations of + the same type are performed (on the same kind of interval and functions, + for a given accuracy): we skip a precomputation of $O(D\log D)$ + elementary functions in accuracy $D$, whose running time has the same order + of magnitude as the evaluation of the integrand. This is in particular + useful for multivariate integrals. + + \misctitle{Specifying the behavior at endpoints} This is done as follows. + An endpoint $a$ is either given as such (a scalar, + real or complex, \kbd{oo} or \kbd{-oo} for $\pm\infty$), or as a two + component vector $[a,\alpha]$, to indicate the behavior of the integrand in a + neighborhood of $a$. + + If $a$ is finite, the code $[a,\alpha]$ means the function has a + singularity of the form $(x-a)^{\alpha}$, up to logarithms. (If $\alpha \ge + 0$, we only assume the function is regular, which is the default assumption.) + If a wrong singularity exponent is used, the result will lose decimals: + \bprog + ? c = -9/10; + ? intnum(x=0, 1, x^c) \\@com assume $x^{-9/10}$ is regular at 0 + %1 = 9.9999839078827082322596783301939063944 + ? intnum(x=[0,c], 1, x^c) \\@com no, it's not + %2 = 10.000000000000000000000000000000000000 + ? intnum(x=[0,c/2], 1, x^c) \\@com using a wrong exponent is bad + %3 = 9.9999999997122749095442279375719919769 + @eprog + + If $a$ is $\pm\infty$, which is coded as \kbd{+oo} or \kbd{-oo}, + the situation is more complicated, and $[\pm\kbd{oo},\alpha]$ means: + + \item $\alpha=0$ (or no $\alpha$ at all, i.e. simply $\pm\kbd{oo}$) + assumes that the integrand tends to zero moderately quickly, at least as + $O(x^{-2})$ but not exponentially fast. + + \item $\alpha>0$ assumes that the function tends to zero exponentially fast + approximately as $\exp(-\alpha|x|)$. This includes oscillating but quickly + decreasing functions such as $\exp(-x)\sin(x)$. + \bprog + ? intnum(x=0, +oo, exp(-2*x)) + *** at top-level: intnum(x=0,+oo,exp(- + *** ^-------------------- + *** exp: exponent (expo) overflow + ? intnum(x=0, [+oo, 2], exp(-2*x)) \\@com OK! + %1 = 0.50000000000000000000000000000000000000 + ? intnum(x=0, [+oo, 3], exp(-2*x)) \\@com imprecise exponent, still OK ! + %2 = 0.50000000000000000000000000000000000000 + ? intnum(x=0, [+oo, 10], exp(-2*x)) \\@com wrong exponent $\Rightarrow$ disaster + %3 = 0.49999999999952372962457451698256707393 + @eprog\noindent As the last exemple shows, the exponential decrease rate + \emph{must} be indicated to avoid overflow, but the method is robust enough + for a rough guess to be acceptable. + + \item $\alpha<-1$ assumes that the function tends to $0$ slowly, like + $x^{\alpha}$. Here the algorithm is less robust and it is essential to give a + sharp $\alpha$, unless $\alpha \le -2$ in which case we use + the default algorithm as if $\alpha$ were missing (or equal to $0$). + \bprog + ? intnum(x=1, +oo, x^(-3/2)) \\ default + %1 = 1.9999999999999999999999999999646391207 + ? intnum(x=1, [+oo,-3/2], x^(-3/2)) \\ precise decrease rate + %2 = 2.0000000000000000000000000000000000000 + ? intnum(x=1, [+oo,-11/10], x^(-3/2)) \\ worse than default + %3 = 2.0000000000000000000000000089298011973 + @eprog + + \smallskip The last two codes are reserved for oscillating functions. + Let $k > 0$ real, and $g(x)$ a nonoscillating function tending slowly to $0$ + (e.g. like a negative power of $x$), then + + \item $\alpha=k * I$ assumes that the function behaves like $\cos(kx)g(x)$. + + \item $\alpha=-k* I$ assumes that the function behaves like $\sin(kx)g(x)$. + + \noindent Here it is critical to give the exact value of $k$. If the + oscillating part is not a pure sine or cosine, one must expand it into a + Fourier series, use the above codings, and sum the resulting contributions. + Otherwise you will get nonsense. Note that $\cos(kx)$, and similarly + $\sin(kx)$, means that very function, and not a translated version such as + $\cos(kx+a)$. Note that the (slower) function \kbd{intnumosc} is more robust + and should be able to integrate much more general quasi-periodic functions + such as fractional parts or Bessel $J$ and $Y$ functions. + + \bprog + ? \pb1664 + ? exponent(intnum(x=0,+oo, sinc(x)) - Pi/2) + time = 308 ms. + %1 = 5 \\ junk + ? exponent(intnum(x=0,[+oo,-I], sinc(x)) - Pi/2) + time = 493 ms. + %2 = -1663 \\ perfect when k is given + ? exponent(intnum(x=0,[+oo,-0.999*I], sinc(x)) - Pi/2) + time = 604 ms. + %3 = -14 \\ junk when k is off + + \\ intnumosc requires the half-period + ? exponent(intnumosc(x=0, sinc(x), Pi) - Pi/2) + time = 20,570 ms. + %4 = -1663 \\ slower but perfect + ? exponent(intnumosc(x=0, sinc(x), Pi, 1) - Pi/2) + time = 7,976 ms. + %4 = -1663 \\ also perfect in fast unsafe mode + ? exponent(intnumosc(x=0, sinc(x), Pi+0.001, 1) - Pi/2) + time = 23,115 ms. + %5 = -1278 \\ loses some accuracy when period is off, but much less + @eprog + + \misctitle{Note} If $f(x)=\cos(kx)g(x)$ where $g(x)$ tends to zero + exponentially fast as $\exp(-\alpha x)$, it is up to the user to choose + between $[\pm\kbd{oo},\alpha]$ and $[\pm\kbd{oo},k* I]$, but a good rule of + thumb is that + if the oscillations are weaker than the exponential decrease, choose + $[\pm\kbd{oo},\alpha]$, otherwise choose $[\pm\kbd{oo},k*I]$, although the + latter can reasonably be used in all cases, while the former cannot. To take + a specific example, in most inverse Mellin transforms, the integrand is a + product of an exponentially decreasing and an oscillating factor. If we + choose the oscillating type of integral we perhaps obtain the best results, + at the expense of having to recompute our functions for a different value of + the variable $z$ giving the transform, preventing us to use a function such + as \kbd{intfuncinit}. On the other hand using the exponential type of + integral, we obtain less accurate results, but we skip expensive + recomputations. See \kbd{intfuncinit} for more explanations. + + \misctitle{Power series limits} + The limits $a$ and $b$ can be power series of nonnegative valuation, + giving a power series expansion for the integral -- provided it exists. + \bprog + ? intnum(t=0,X + O(X^3), exp(t)) + %4 = 1.000...*X - 0.5000...*X^2 + O(X^3) + ? bestappr( intnum(t=0,X + O(X^17), exp(t)) )- exp(X) + 1 + %5 = O(X^17) + @eprog\noindent The valuation of the limit cannot be negative + since $\int_{0}^{1/X}(1+t^{2})^{-1}\, dt = \pi/2 - \kbd{sign}(X)+O(X^{2})$. + + Polynomials and rational functions are also allowed and + converted to power series using current \kbd{seriesprecision}: + \bprog + ? bestappr( intnum(t=1,1+X, 1/t) ) + %6 = X - 1/2*X^2 + 1/3*X^3 - 1/4*X^4 + [...] + 1/15*X^15 + O(X^16) + @eprog\noindent + The function does not work if the integral is singular with the constant + coefficient of the series as limit: + \bprog + ? intnum(t=X^2+O(X^4),1, 1/sqrt(t)) + %8 = 2.000... - 6.236608109630992528 E28*X^2 + O(X^4) + @eprog\noindent + however you can use + \bprog + ? intnum(t=[X^2+O(X^4),-1/2],1, 1/sqrt(t)) + %10 = 2.000000000000000000000000000-2.000000000000000000000000000*X^2+O(X^4) + @eprog\noindent whis is translated internally to + \bprog + ? intnum(t=[0,-1/2],1, 1/sqrt(t))-intnum(t=[0,-1/2],X^2+O(X^4), 1/sqrt(t)) + @eprog\noindent + For this form the argument \var{tab} can be used only as an integer, not a + table precomputed by \kbd{intnuminit}. + + \smallskip + + We shall now see many examples to get a feeling for what the various + parameters achieve. All examples below assume precision is set to $115$ + decimal digits. We first type + \bprog + ? \p 115 + @eprog + + \misctitle{Apparent singularities} In many cases, apparent singularities + can be ignored. For instance, if $f(x) = 1 + /(\exp(x)-1) - \exp(-x)/x$, then $\int_{0}^{\infty} f(x)\,dx=\gamma$, Euler's + constant \kbd{Euler}. But + + \bprog + ? f(x) = 1/(exp(x)-1) - exp(-x)/x + ? intnum(x = 0, [oo,1], f(x)) - Euler + %1 = 0.E-115 + @eprog\noindent + But close to $0$ the function $f$ is computed with an enormous loss of + accuracy, and we are in fact lucky that it get multiplied by weights which are + sufficiently close to $0$ to hide this: + \bprog + ? f(1e-200) + %2 = -3.885337784451458142 E84 + @eprog + + A more robust solution is to define the function differently near special + points, e.g. by a Taylor expansion + \bprog + ? F = truncate( f(t + O(t^10)) ); \\@com expansion around t = 0 + ? poldegree(F) + %4 = 7 + ? g(x) = if (x > 1e-18, f(x), subst(F,t,x)); \\@com note that $7 \cdot 18 > 105$ + ? intnum(x = 0, [oo,1], g(x)) - Euler + %2 = 0.E-115 + @eprog\noindent It is up to the user to determine constants such as the + $10^{-18}$ and $10$ used above. + + \misctitle{True singularities} With true singularities the result is worse. + For instance + + \bprog + ? intnum(x = 0, 1, x^(-1/2)) - 2 + %1 = -3.5... E-68 \\@com only $68$ correct decimals + + ? intnum(x = [0,-1/2], 1, x^(-1/2)) - 2 + %2 = 0.E-114 \\@com better + @eprog + + \misctitle{Oscillating functions} + + \bprog + ? intnum(x = 0, oo, sin(x) / x) - Pi/2 + %1 = 16.19.. \\@com nonsense + ? intnum(x = 0, [oo,1], sin(x)/x) - Pi/2 + %2 = -0.006.. \\@com bad + ? intnum(x = 0, [oo,-I], sin(x)/x) - Pi/2 + %3 = 0.E-115 \\@com perfect + ? intnum(x = 0, [oo,-I], sin(2*x)/x) - Pi/2 \\@com oops, wrong $k$ + %4 = 0.06... + ? intnum(x = 0, [oo,-2*I], sin(2*x)/x) - Pi/2 + %5 = 0.E-115 \\@com perfect + + ? intnum(x = 0, [oo,-I], sin(x)^3/x) - Pi/4 + %6 = -0.0008... \\@com bad + ? sin(x)^3 - (3*sin(x)-sin(3*x))/4 + %7 = O(x^17) + @eprog\noindent + We may use the above linearization and compute two oscillating integrals with + endpoints \kbd{[oo, -I]} and \kbd{[oo, -3*I]} respectively, or + notice the obvious change of variable, and reduce to the single integral + ${1\over 2}\int_{0}^{\infty} \sin(x)/x\,dx$. We finish with some more + complicated examples: + + \bprog + ? intnum(x = 0, [oo,-I], (1-cos(x))/x^2) - Pi/2 + %1 = -0.0003... \\@com bad + ? intnum(x = 0, 1, (1-cos(x))/x^2) \ + + intnum(x = 1, oo, 1/x^2) - intnum(x = 1, [oo,I], cos(x)/x^2) - Pi/2 + %2 = 0.E-115 \\@com perfect + + ? intnum(x = 0, [oo, 1], sin(x)^3*exp(-x)) - 0.3 + %3 = -7.34... E-55 \\@com bad + ? intnum(x = 0, [oo,-I], sin(x)^3*exp(-x)) - 0.3 + %4 = 8.9... E-103 \\@com better. Try higher $m$ + ? tab = intnuminit(0,[oo,-I], 1); \\@com double number of sampling points + ? intnum(x = 0, oo, sin(x)^3*exp(-x), tab) - 0.3 + %6 = 0.E-115 \\@com perfect + @eprog + + \misctitle{Warning} Like \tet{sumalt}, \kbd{intnum} often assigns a + reasonable value to diverging integrals. Use these values at your own risk! + For example: + + \bprog + ? intnum(x = 0, [oo, -I], x^2*sin(x)) + %1 = -2.0000000000... + @eprog\noindent + Note the formula + $$ \int_{0}^{\infty} \sin(x)x^{-s}\,dx = \cos(\pi s/2) \Gamma(1-s)\;, $$ + a priori valid only for $0 < \Re(s) < 2$, but the right hand side provides an + analytic continuation which may be evaluated at $s = -2$\dots + + \misctitle{Multivariate integration} + Using successive univariate integration with respect to different formal + parameters, it is immediate to do naive multivariate integration. But it is + important to use a suitable \kbd{intnuminit} to precompute data for the + \emph{internal} integrations at least! + + For example, to compute the double integral on the unit disc $x^{2}+y^{2}\le1$ + of the function $x^{2}+y^{2}$, we can write + \bprog + ? tab = intnuminit(-1,1); + ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab),tab) - Pi/2 + %2 = -7.1... E-115 \\@com OK + + @eprog\noindent + The first \var{tab} is essential, the second optional. Compare: + + \bprog + ? tab = intnuminit(-1,1); + time = 4 ms. + ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2)); + time = 3,092 ms. \\@com slow + ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab), tab); + time = 252 ms. \\@com faster + ? intnum(x=-1,1, intnum(y=-sqrt(1-x^2),sqrt(1-x^2), x^2+y^2, tab)); + time = 261 ms. \\@com the \emph{internal} integral matters most + @eprog + + \synt{intnum}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b,GEN tab, long prec}, + where an omitted \var{tab} is coded as \kbd{NULL}. + +Function: intnumgauss +Class: basic +Section: sums +C-Name: intnumgauss0 +Prototype: V=GGEDGp +Help: intnumgauss(X=a,b,expr,{tab}): numerical integration of expr from + a to b, a compact interval, with respect to X using Gauss-Legendre + quadrature. tab is either omitted (and will be recomputed) or + precomputed with intnumgaussinit. +Wrapper: (,,G) +Description: + (gen,gen,gen,?gen):gen:prec intnumgauss(${3 cookie}, ${3 wrapper}, $1, $2, $4, $prec) +Doc: numerical integration of \var{expr} on the compact interval $[a,b]$ with + respect to $X$ using Gauss-Legendre quadrature; \kbd{tab} is either omitted + or precomputed with \kbd{intnumgaussinit}. As a convenience, it can be an + integer $n$ in which case we call + \kbd{intnumgaussinit}$(n)$ and use $n$-point quadrature. + \bprog + ? test(n, b = 1) = T=intnumgaussinit(n);\ + intnumgauss(x=-b,b, 1/(1+x^2),T) - 2*atan(b); + ? test(0) \\ default + %1 = -9.490148553624725335 E-22 + ? test(40) + %2 = -6.186629001816965717 E-31 + ? test(50) + %3 = -1.1754943508222875080 E-38 + ? test(50, 2) \\ double interval length + %4 = -4.891779568527713636 E-21 + ? test(90, 2) \\ n must almost be doubled as well! + %5 = -9.403954806578300064 E-38 + @eprog\noindent On the other hand, we recommend to split the integral + and change variables rather than increasing $n$ too much: + \bprog + ? f(x) = 1/(1+x^2); + ? b = 100; + ? intnumgauss(x=0,1, f(x)) + intnumgauss(x=1,1/b, f(1/x)*(-1/x^2)) - atan(b) + %3 = -1.0579449157400587572 E-37 + @eprog + +Function: intnumgaussinit +Class: basic +Section: sums +C-Name: intnumgaussinit +Prototype: D0,L,p +Help: intnumgaussinit({n}): initialize tables for n-point Gauss-Legendre + integration on a compact interval. +Doc: initialize tables for $n$-point Gauss-Legendre integration of + a smooth function $f$ on a compact interval $[a,b]$. If $n$ is omitted, make a + default choice $n \approx B / 4$, where $B$ is + \kbd{realbitprecision}, suitable for analytic functions on $[-1,1]$. + The error is bounded by + $$ + \dfrac{(b-a)^{2n+1} (n!)^{4}}{(2n+1)!(2n)!} \dfrac{f^{(2n)}}{(2n)!} (\xi) , + \qquad a < \xi < b. + $$ + If $r$ denotes the distance of the nearest pole to the interval $[a,b]$, + then this is of the order of $((b-a) / (4r))^{2n}$. In particular, the + integral must be subdivided if the interval length $b - a$ becomes close to + $4r$. The default choice $n \approx B / 4$ makes this quantity of order + $2^{-B}$ when $b - a = r$, as is the case when integrating $1/(1+t)$ on + $[0,1]$ for instance. If the interval length increases, $n$ should be + increased as well. + + Specifically, the function returns a pair of vectors $[x,w]$, where $x$ + contains the nonnegative roots of the $n$-th Legendre polynomial $P_{n}$ and + $w$ the corresponding Gaussian integration weights + $Q_{n}(x_{j})/P'_{n}(x_{j}) = 2 / ((1-x_{j}^{2})P'_{n}(x_{j}))^{2}$ such that + $$ \int_{-1}^{1} f(t)\, dt \approx \sum_{j} w_{j} f(x_{j})\;. $$ + + \bprog + ? T = intnumgaussinit(); + ? intnumgauss(t=-1,1,exp(t), T) - exp(1)+exp(-1) + %1 = -5.877471754111437540 E-39 + ? intnumgauss(t=-10,10,exp(t), T) - exp(10)+exp(-10) + %2 = -8.358367809712546836 E-35 + ? intnumgauss(t=-1,1,1/(1+t^2), T) - Pi/2 \\ b - a = 2r + %3 = -9.490148553624725335 E-22 \\ ... loses half the accuracy + + ? T = intnumgaussinit(50); + ? intnumgauss(t=-1,1,1/(1+t^2), T) - Pi/2 + %5 = -1.1754943508222875080 E-38 + ? intnumgauss(t=-5,5,1/(1+t^2), T) - 2*atan(5) + %6 = -1.2[...]E-8 + @eprog + On the other hand, we recommend to split the integral and change variables + rather than increasing $n$ too much, see \tet{intnumgauss}. + +Function: intnuminit +Class: basic +Section: sums +C-Name: intnuminit +Prototype: GGD0,L,p +Help: intnuminit(a,b,{m=0}): initialize tables for integrations from a to b. + See help for intnum for coding of a and b. Possible types: compact interval, + semi-compact (one extremity at + or - infinity) or R, and very slowly, slowly + or exponentially decreasing, or sine or cosine oscillating at infinities. +Doc: initialize tables for integration from + $a$ to $b$, where $a$ and $b$ are coded as in \kbd{intnum}. Only the + compactness, the possible existence of singularities, the speed of decrease + or the oscillations at infinity are taken into account, and not the values. + For instance {\tt intnuminit(-1,1)} is equivalent to {\tt intnuminit(0,Pi)}, + and {\tt intnuminit([0,-1/2],oo)} is equivalent to + {\tt intnuminit([-1,-1/2], -oo)}; on the other hand, the order matters + and + {\tt intnuminit([0,-1/2], [1,-1/3])} is \emph{not} equivalent to + {\tt intnuminit([0,-1/3], [1,-1/2])} ! + + If $m$ is present, it must be nonnegative and we multiply the default + number of sampling points by $2^{m}$ (increasing the running time by a + similar factor). + + The result is technical and liable to change in the future, but we document + it here for completeness. Let $x=\phi(t)$, $t\in ]-\infty,\infty[$ be an + internally chosen change of variable, achieving double exponential decrease of + the integrand at infinity. The integrator \kbd{intnum} will compute + $$ h \sum_{|n| < N} \phi'(nh) F(\phi(nh)) $$ + for some integration step $h$ and truncation parameter $N$. + In basic use, let + \bprog + [h, x0, w0, xp, wp, xm, wm] = intnuminit(a,b); + @eprog + + \item $h$ is the integration step + + \item $x_{0} = \phi(0)$ and $w_{0} = \phi'(0)$, + + \item \var{xp} contains the $\phi(nh)$, $0 < n < N$, + + \item \var{xm} contains the $\phi(nh)$, $0 < -n < N$, or is empty. + + \item \var{wp} contains the $\phi'(nh)$, $0 < n < N$, + + \item \var{wm} contains the $\phi'(nh)$, $0 < -n < N$, or is empty. + + The arrays \var{xm} and \var{wm} are left empty when $\phi$ is an odd + function. In complicated situations, + \kbd{intnuminit} may return up to $3$ such arrays, corresponding + to a splitting of up to $3$ integrals of basic type. + + If the functions to be integrated later are of the form $F = f(t) k(t,z)$ + for some kernel $k$ (e.g. Fourier, Laplace, Mellin, \dots), it is + useful to also precompute the values of $f(\phi(nh))$, which is accomplished + by \tet{intfuncinit}. The hard part is to determine the behavior + of $F$ at endpoints, depending on $z$. + +Function: intnumosc +Class: basic +Section: sums +C-Name: intnumosc0 +Prototype: V=GEGD0,L,DGp +Help: intnumosc(x=a,expr,H,{flag=0},{tab}): numerical integration from a + to oo of oscillating quasi-periodic function expr of half-period H. + tab is either omitted (and will be recomputed) or precomputed with + intnumgaussinit; flag is either 0 (Sidi extrapolation, safe mode), 1 (Sidi + extrapolation, unsafe mode), 2 (sumalt), 3 (sumnumlagrange), 4 (sumpos). +Doc: numerical integration from $a$ to $\infty$ of oscillating + quasi-periodic function \var{expr} of half-period $H$, meaning that we + at least expect the distance between the function's consecutive zeros to be + close to $H$: the sine or cosine functions ($H = \pi$) are paradigmatic + examples, but the Bessel $J_{\nu}$ or $Y_{\nu}$ functions ($H = \pi/2$) can + also be handled. The integral from $a$ to $\infty$ is computed + by summing the integral between two consecutive multiples of $H$; + \fl determines the summation algorithm used: either $0$ (Sidi extrapolation, + safe mode), 1 (Sidi extrapolation, unsafe mode), 2 (\kbd{sumalt}), + 3 (\kbd{sumnumlagrange}) or 4 (\kbd{sumpos}). For the last two modes + (Lagrange and Sumpos), one should input the period $2H$ instead of the + half-period $H$. + + The default is $\fl = 0$; Sidi summation should be the most + robust algorithm; you can try it in unsafe mode when the integrals between + two consecutive multiples of $H$ form an alternating series, this should be + about twice faster than the default and not lose accuracy. Sumpos should be + by far the slowest method, but also very robust and may be able to handle + integrals where Sidi fails. Sumalt should be fast but often wrong, + especially when the integrals between two consecutive multiples of $H$ + do not form an alternating series), and Lagrange should be as fast as Sumalt + but more often wrong. + + When one of the Sidi modes runs into difficulties, it will return the result + to the accuracy believed to be correct (the other modes do not perform + extrapolation and do not have this property) : + \bprog + ? f(x)=besselj(0,x)^4*log(x+1); + ? \pb384 + ? intnumosc(x = 0, f(x), Pi) + %1 = 0.4549032054850867417 \\ fewer digits than expected ! + ? bitprecision(%) + %2 = 64 + ? \g1 \\ increase debug level to see diagnostics + ? intnumosc(x = 0, f(x), Pi) + sumsidi: reached accuracy of 23 bits. + %2 = 0.4549032054850867417 + @eprog\noindent The algorithm could extrapolate the series to 23 bits of + accuracy, then diverged. So only the absolute error is likely to be + around $2^{-23}$ instead of the possible $2^{-64}$ (or the requested + $2^{-384}$). We'll come back to this example at the end. + + In case of difficulties, you may try to replace the half-(quasi)-period $H$ + by a multiple, such as the quasi-period $2H$: since we do not expect + alternating behaviour, \kbd{sumalt} mode will almost surely be broken, but + others may improve, in particular Lagrange or Sumpos. + + \kbd{tab} is either omitted or precomputed with \kbd{intnumgaussinit}; + if using Sidi summation in safe mode ($\fl = 0$) \emph{and} precompute + \kbd{tab}, you should use a precision roughly 50\% larger than the target + (this is not necessary for any of the other summations). + + First an alternating example: + \bprog + ? \pb384 + \\ Sidi, safe mode + ? exponent(intnumosc(x=0,sinc(x),Pi) - Pi/2) + time = 183 ms. + %1 = -383 + ? exponent(intnumosc(x=0,sinc(x),2*Pi) - Pi/2) + time = 224 ms. + %2 = -383 \\ also works with 2H, a little slower + + \\ Sidi, unsafe mode + ? exponent(intnumosc(x=0,sinc(x),Pi,1) - Pi/2) + time = 79 ms. + %3 = -383 \\ alternating: unsafe mode is fine and almost twice faster + ? exponent(intnumosc(x=0,sinc(x),2*Pi,1) - Pi/2) + time = 86 ms. + %4 = -285 \\ but this time 2H loses accuracy + + \\ Sumalt + ? exponent(intnumosc(x=0,sinc(x),Pi,2) - Pi/2) + time = 115 ms. \\ sumalt is just as accurate and fast + %5 = -383 + ? exponent(intnumosc(x=0,sinc(x),2*Pi,2) - Pi/2) + time = 115 ms. + %6 = -10 \\ ...but breaks completely with 2H + + \\ Lagrange + ? exponent(intnumosc(x=0,sinc(x),Pi,2) - Pi/2) + time = 100 ms. \\ junk + %7 = 224 + ? exponent(intnumosc(x=0,sinc(x),2*Pi,2) - Pi/2) + time = 100 ms. + %8 = -238 \\ ...a little better with 2H + + \\ Sumpos + ? exponent(intnumosc(x=0,sinc(x),Pi,4) - Pi/2) + time = 17,961 ms. + %9 = 7 \\ junk; slow + ? exponent(intnumosc(x=0,sinc(x),2*Pi,4) - Pi/2) + time = 19,105 ms. + %10 = -4 \\ still junk + @eprog + + Now a non-alternating one: + \bprog + ? exponent(intnumosc(x=0,sinc(x)^2,Pi) - Pi/2) + time = 277 ms. + %1 = -383 \\ safe mode is still perfect + ? exponent(intnumosc(x=0,sinc(x)^2,Pi,1) - Pi/2) + time = 97 ms. + %2 = -284 \\ non-alternating; this time, Sidi's unsafe mode loses accuracy + ? exponent(intnumosc(x=0,sinc(x)^2,Pi,2) - Pi/2) + time = 113 ms. + %3 = -10 \\ this time sumalt fails completely + ? exponent(intnumosc(x=0,sinc(x)^2,Pi,3) - Pi/2) + time = 103 ms. + %4 = -237 \\ Lagrange loses accuracy (same with 2H = 2*Pi) + ? exponent(intnumosc(x=0,sinc(x)^2,Pi,4) - Pi/2) + time = 17,681 ms. + %4 = -381 \\ and Sumpos is good but slow (perfect with 2H) + @eprog + + Exemples of a different flavour: + \bprog + ? exponent(intnumosc(x = 0, besselj(0,x)*sin(3*x), Pi) - 1/sqrt(8)) + time = 4,615 ms. + %1 = -385 \\ more expensive but correct + ? exponent(intnumosc(x = 0, besselj(0,x)*sin(3*x), Pi, 1) - 1/sqrt(8)) + time = 1,424 ms. + %2 = -279 \\ unsafe mode loses some accuracy (other modes return junk) + + ? S = log(2*Pi)- Euler - 1; + ? exponent(intnumosc(t=1, (frac(t)/t)^2, 1/2) - S) + time = 21 ms. + %4 = -6 \\ junk + ? exponent(intnumosc(t=1, (frac(t)/t)^2, 1) - S) + time = 66ms. + %5 = -384 \\ perfect with 2H + ? exponent(intnumosc(t=1, (frac(t)/t)^2, 1, 1) - S) + time = 20 ms. + %6 = -286 \\ unsafe mode loses accuracy + ? exponent(intnumosc(t=1, (frac(t)/t)^2, 1, 3) - S) + time = 30 ms. + %7 = -236 \\ and so does Lagrange (Sumalt fails) + ? exponent(intnumosc(t=1, (frac(t)/t)^2, 1, 4) - S) + time = 2,315 ms. + %8 = -382 \\ Sumpos is perfect but slow + @eprog\noindent Again, Sidi extrapolation behaves well, especially in safe + mode, but $2H$ is required here. + + If the integrand has singularities close to the interval of integration, + it is advisable to split the integral in two: use the more robust \kbd{intnum} + to handle the singularities, then \kbd{intnumosc} for the remainder: + \bprog + ? \p38 + ? f(x) = besselj(0,x)^3 * log(x); \\ mild singularity at 0 + ? g() = intnumosc(x = 0, f(x), Pi); \\ direct + ? h() = intnum(x = 0, Pi, f(x)) + intnumosc(x = Pi, f(x), Pi); \\ split at Pi + ? G = g(); + time = 293 ms. + ? H = h(); + time = 320 ms. \\ about as fast + ? exponent(G-H) + %6 = -12 \\ at least one of them is junk + ? \p77 \\ increase accuracy + ? G2=g(); H2=h(); + ? exponent(G - G2) + %8 = -13 \\ g() is not consistent + ? exponent(H - H2) + %9 = -128 \\ not a proof, but h() looks good + @eprog\noindent Finally, here is an exemple where all methods fail, even + when splitting the integral, except Sumpos: + \bprog + ? \p38 + ? f(x)=besselj(0,x)^4*log(x+1); + ? F = intnumosc(x=0,f(x), Pi, 4) + time = 2,437 ms. + %2 = 0.45489838778971732178155161172638343214 + ? \p76 \\ double accuracy to check + ? exponent(F - intnumosc(x = 0,f(x), Pi, 4)) + time = 18,817 ms. + %3 = -122 \\ F was almost perfect + @eprog + +Function: intnumromb +Class: basic +Section: sums +C-Name: intnumromb0 +Prototype: V=GGED0,L,b +Help: intnumromb(X=a,b,expr,{flag=0}): numerical integration of expr (smooth in + ]a,b[) from a to b with respect to X. flag is optional and mean 0: default. + expr can be evaluated exactly on [a,b]; 1: general function; 2: a or b can be + plus or minus infinity (chosen suitably), but of same sign; 3: expr has only + limits at a or b. +Wrapper: (,,G) +Description: + (gen,gen,gen,?small):gen:prec intnumromb(${3 cookie}, ${3 wrapper}, $1, $2, $4, $bitprec) +Doc: numerical integration of \var{expr} (smooth in $]a,b[$), with respect to + $X$. Suitable for low accuracy; if \var{expr} is very regular (e.g. analytic + in a large region) and high accuracy is desired, try \tet{intnum} first. + + Set $\fl=0$ (or omit it altogether) when $a$ and $b$ are not too large, the + function is smooth, and can be evaluated exactly everywhere on the interval + $[a,b]$. + + If $\fl=1$, uses a general driver routine for doing numerical integration, + making no particular assumption (slow). + + $\fl=2$ is tailored for being used when $a$ or $b$ are infinite using the + change of variable $t = 1/X$. One \emph{must} have $ab>0$, and in fact if + for example $b=+\infty$, then it is preferable to have $a$ as large as + possible, at least $a\ge1$. + + If $\fl=3$, the function is allowed to be undefined + at $a$ (but right continuous) or $b$ (left continuous), + for example the function $\sin(x)/x$ between $x=0$ and $1$. + + The user should not require too much accuracy: \tet{realprecision} about + 30 decimal digits (\tet{realbitprecision} about 100 bits) is OK, + but not much more. In addition, analytical cleanup of the integral must have + been done: there must be no singularities in the interval or at the + boundaries. In practice this can be accomplished with a change of + variable. Furthermore, for improper integrals, where one or both of the + limits of integration are plus or minus infinity, the function must decrease + sufficiently rapidly at infinity, which can often be accomplished through + integration by parts. Finally, the function to be integrated should not be + very small (compared to the current precision) on the entire interval. This + can of course be accomplished by just multiplying by an appropriate constant. + + Note that \idx{infinity} can be represented with essentially no loss of + accuracy by an appropriate huge number. However beware of real underflow + when dealing with rapidly decreasing functions. For example, in order to + compute the $\int_{0}^{\infty} e^{-x^{2}}\,dx$ to 38 decimal digits, then + one can set infinity equal to 10 for example, and certainly not to + \kbd{1e1000}. + %\syn{NO} + + The library syntax is \fun{GEN}{intnumromb}{void *E, GEN (*eval)(void*,GEN), GEN a, GEN b, long flag, long bitprec}, where \kbd{eval}$(x, E)$ returns the value of the + function at $x$. You may store any additional information required by + \kbd{eval} in $E$, or set it to \kbd{NULL}. + +Function: isfundamental +Class: basic +Section: number_theoretical +C-Name: isfundamental +Prototype: lG +Help: isfundamental(D): true(1) if D is a fundamental discriminant + (including 1), false(0) if not. +Description: + (int):bool Z_isfundamental($1) + (gen):bool isfundamental($1) +Doc: true (1) if $D$ is equal to 1 or to the discriminant of a quadratic + field, false (0) otherwise. $D$ can be input in factored form as for + arithmetic functions: + \bprog + ? isfundamental(factor(-8)) + %1 = 1 + \\ count fundamental discriminants up to 10^8 + ? c = 0; forfactored(d = 1, 10^8, if (isfundamental(d), c++)); c + time = 40,840 ms. + %2 = 30396325 + ? c = 0; for(d = 1, 10^8, if (isfundamental(d), c++)); c + time = 1min, 33,593 ms. \\ slower ! + %3 = 30396325 + @eprog + +Function: ispolygonal +Class: basic +Section: number_theoretical +C-Name: ispolygonal +Prototype: lGGD& +Help: ispolygonal(x,s,{&N}): true(1) if x is an s-gonal number, false(0) if + not (s > 2). If N is given set it to n if x is the n-th s-gonal number. +Doc: true (1) if the integer $x$ is an s-gonal number, false (0) if not. + The parameter $s > 2$ must be a \typ{INT}. If $N$ is given, set it to $n$ + if $x$ is the $n$-th $s$-gonal number. + \bprog + ? ispolygonal(36, 3, &N) + %1 = 1 + ? N + @eprog + +Function: ispower +Class: basic +Section: number_theoretical +C-Name: ispower +Prototype: lGDGD& +Help: ispower(x,{k},{&n}): if k > 0 is given, return true (1) if x is a k-th + power, false (0) if not. If k is omitted, return the maximal k >= 2 such + that x = n^k is a perfect power, or 0 if no such k exist. + If n is present, and the function returns a nonzero result, set n to the + k-th root of x. +Description: + (int):small Z_isanypower($1, NULL) + (int, &int):small Z_isanypower($1, &$2) +Doc: if $k$ is given, returns true (1) if $x$ is a $k$-th power, false + (0) if not. What it means to be a $k$-th power depends on the type of + $x$; see \tet{issquare} for details. + + If $k$ is omitted, only integers and fractions are allowed for $x$ and the + function returns the maximal $k \geq 2$ such that $x = n^{k}$ is a perfect + power, or 0 if no such $k$ exist; in particular \kbd{ispower(-1)}, + \kbd{ispower(0)}, and \kbd{ispower(1)} all return $0$. + + If a third argument $\&n$ is given and $x$ is indeed a $k$-th power, sets + $n$ to a $k$-th root of $x$. + + \noindent For a \typ{FFELT} \kbd{x}, instead of omitting \kbd{k} (which is + not allowed for this type), it may be natural to set + \bprog + k = (x.p ^ x.f - 1) / fforder(x) + @eprog +Variant: Also available is + \fun{long}{gisanypower}{GEN x, GEN *pty} ($k$ omitted). + +Function: ispowerful +Class: basic +Section: number_theoretical +C-Name: ispowerful +Prototype: lG +Help: ispowerful(x): true(1) if x is a powerful integer (valuation at all + primes dividing x is greater than 1), false(0) if not. +Doc: true (1) if $x$ is a powerful integer, false (0) if not; + an integer is powerful if and only if its valuation at all primes dividing + $x$ is greater than 1. + \bprog + ? ispowerful(50) + %1 = 0 + ? ispowerful(100) + %2 = 1 + ? ispowerful(5^3*(10^1000+1)^2) + %3 = 1 + @eprog + +Function: isprime +Class: basic +Section: number_theoretical +C-Name: gisprime +Prototype: GD0,L, +Help: isprime(x,{flag=0}): true(1) if x is a (proven) prime number, false(0) + if not. If flag is 0 or omitted, use a combination of algorithms. If flag is + 1, the primality is certified by the Pocklington-Lehmer Test. If flag is 2, + the primality is certified using the APRCL test. If flag is 3, use ECPP. +Description: + (int, ?0):bool isprime($1) + (gen, ?small):gen gisprime($1, $2) +Doc: true (1) if $x$ is a prime + number, false (0) otherwise. A prime number is a positive integer having + exactly two distinct divisors among the natural numbers, namely 1 and + itself. + + This routine proves or disproves rigorously that a number is prime, which can + be very slow when $x$ is indeed a large prime integer. For instance + a $1000$ digits prime should require 15 to 30 minutes with default algorithms. + Use \tet{ispseudoprime} to quickly check for compositeness. Use + \tet{primecert} in order to obtain a primality proof instead of a yes/no + answer; see also \kbd{factor}. + + The function accepts vector/matrices arguments, and is then + applied componentwise. + + If $\fl=0$, use a combination of + + \item Baillie-Pomerance-Selfridge-Wagstaff compositeness test + (see \tet{ispseudoprime}), + + \item Selfridge ``$p-1$'' test if $x-1$ is smooth enough, + + \item Adleman-Pomerance-Rumely-Cohen-Lenstra (APRCL) for general + medium-sized $x$ (less than 1500 bits), + + \item Atkin-Morain's Elliptic Curve Primality Prover (ECPP) for general + large $x$. + + If $\fl=1$, use Selfridge-Pocklington-Lehmer ``$p-1$'' test; this requires + partially factoring various auxilliary integers and is likely to be very slow. + + If $\fl=2$, use APRCL only. + + If $\fl=3$, use ECPP only. + +Function: isprimepower +Class: basic +Section: number_theoretical +C-Name: isprimepower +Prototype: lGD& +Help: isprimepower(x,{&n}): if x = p^k is a prime power (p prime, k > 0), + return k, else return 0. If n is present, and the function returns a nonzero + result, set n to p, the k-th root of x. +Doc: if $x = p^{k}$ is a prime power ($p$ prime, $k > 0$), return $k$, else + return 0. If a second argument $\&n$ is given and $x$ is indeed + the $k$-th power of a prime $p$, sets $n$ to $p$. + +Function: ispseudoprime +Class: basic +Section: number_theoretical +C-Name: gispseudoprime +Prototype: GD0,L, +Help: ispseudoprime(x,{flag}): true(1) if x is a strong pseudoprime, false(0) + if not. If flag is 0 or omitted, use BPSW test, otherwise use strong + Rabin-Miller test for flag randomly chosen bases. +Description: + (int,?0):bool BPSW_psp($1) + (int,#small):bool millerrabin($1,$2) + (int,small):bool ispseudoprime($1, $2) + (gen,?small):gen gispseudoprime($1, $2) +Doc: true (1) if $x$ is a strong pseudo + prime (see below), false (0) otherwise. If this function returns false, $x$ + is not prime; if, on the other hand it returns true, it is only highly likely + that $x$ is a prime number. Use \tet{isprime} (which is of course much + slower) to prove that $x$ is indeed prime. + The function accepts vector/matrices arguments, and is then applied + componentwise. + + If $\fl = 0$, checks whether $x$ has no small prime divisors (up to $101$ + included) and is a Baillie-Pomerance-Selfridge-Wagstaff pseudo prime. + Such a pseudo prime passes a Rabin-Miller test for base $2$, + followed by a Lucas test for the sequence $(P,1)$, where $P \geq 3$ + is the smallest odd integer such that $P^{2} - 4$ is not a square mod $x$. + (Technically, we are using an ``almost extra strong Lucas test'' that + checks whether $V_{n}$ is $\pm 2$, without computing $U_{n}$.) + + There are no known composite numbers passing the above test, although it is + expected that infinitely many such numbers exist. In particular, all + composites $\leq 2^{64}$ are correctly detected (checked using + \url{https://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html}). + + If $\fl > 0$, checks whether $x$ is a strong Miller-Rabin pseudo prime for + $\fl$ randomly chosen bases (with end-matching to catch square roots of $-1$). + +Function: ispseudoprimepower +Class: basic +Section: number_theoretical +C-Name: ispseudoprimepower +Prototype: lGD& +Help: ispseudoprimepower(x,{&n}): if x = p^k is a pseudo-prime power (p + pseudo-prime, k > 0), + return k, else return 0. If n is present, and the function returns a nonzero + result, set n to p, the k-th root of x. +Doc: if $x = p^{k}$ is a pseudo-prime power ($p$ pseudo-prime as per + \tet{ispseudoprime}, $k > 0$), return $k$, else + return 0. If a second argument $\&n$ is given and $x$ is indeed + the $k$-th power of a prime $p$, sets $n$ to $p$. + + More precisely, $k$ is always the largest integer such that $x = n^{k}$ for + some integer $n$ and, when $n \leq 2^{64}$ the function returns $k > 0$ if and + only if $n$ is indeed prime. When $n > 2^{64}$ is larger than the threshold, + the function may return $1$ even though $n$ is composite: it only passed + an \kbd{ispseudoprime(n)} test. + +Function: issquare +Class: basic +Section: number_theoretical +C-Name: issquareall +Prototype: lGD& +Help: issquare(x,{&n}): true(1) if x is a square, false(0) if not. If n is + given puts the exact square root there if it was computed. +Description: + (int):bool Z_issquare($1) + (gen):bool issquare($1) + (int, &int):bool Z_issquareall($1, &$2) + (gen, &gen):bool issquareall($1, &$2) +Doc: true (1) if $x$ is a square, false (0) + if not. What ``being a square'' means depends on the type of $x$: all + \typ{COMPLEX} are squares, as well as all nonnegative \typ{REAL}; for + exact types such as \typ{INT}, \typ{FRAC} and \typ{INTMOD}, squares are + numbers of the form $s^{2}$ with $s$ in $\Z$, $\Q$ and $\Z/N\Z$ respectively. + \bprog + ? issquare(3) \\ as an integer + %1 = 0 + ? issquare(3.) \\ as a real number + %2 = 1 + ? issquare(Mod(7, 8)) \\ in Z/8Z + %3 = 0 + ? issquare( 5 + O(13^4) ) \\ in Q_13 + %4 = 0 + @eprog + If $n$ is given, a square root of $x$ is put into $n$. + \bprog + ? issquare(4, &n) + %1 = 1 + ? n + %2 = 2 + @eprog + For polynomials, either we detect that the characteristic is 2 (and check + directly odd and even-power monomials) or we assume that $2$ is invertible + and check whether squaring the truncated power series for the square root + yields the original input. + + For \typ{POLMOD} $x$, we only support \typ{POLMOD}s of \typ{INTMOD}s + encoding finite fields, assuming without checking that the intmod modulus + $p$ is prime and that the polmod modulus is irreducible modulo $p$. + \bprog + ? issquare(Mod(Mod(2,3), x^2+1), &n) + %1 = 1 + ? n + %2 = Mod(Mod(2, 3)*x, Mod(1, 3)*x^2 + Mod(1, 3)) + @eprog +Variant: Also available is \fun{long}{issquare}{GEN x}. Deprecated + GP-specific functions \fun{GEN}{gissquare}{GEN x} and + \fun{GEN}{gissquareall}{GEN x, GEN *pt} return \kbd{gen\_0} and \kbd{gen\_1} + instead of a boolean value. + +Function: issquarefree +Class: basic +Section: number_theoretical +C-Name: issquarefree +Prototype: lG +Help: issquarefree(x): true(1) if x is squarefree, false(0) if not. +Description: + (gen):bool issquarefree($1) +Doc: true (1) if $x$ is squarefree, false (0) if not. Here $x$ can be an + integer or a polynomial with coefficients in an integral domain. + \bprog + ? issquarefree(12) + %1 = 0 + ? issquarefree(6) + %2 = 1 + ? issquarefree(x^3+x^2) + %3 = 0 + ? issquarefree(Mod(1,4)*(x^2+x+1)) \\ Z/4Z is not a domain ! + *** at top-level: issquarefree(Mod(1,4)*(x^2+x+1)) + *** ^-------------------------------- + *** issquarefree: impossible inverse in Fp_inv: Mod(2, 4). + @eprog\noindent A polynomial is declared squarefree if \kbd{gcd}$(x,x')$ is + $1$. In particular a nonzero polynomial with inexact coefficients is + considered to be squarefree. Note that this may be inconsistent with + \kbd{factor}, which first rounds the input to some exact approximation before + factoring in the apropriate domain; this is correct when the input is not + close to an inseparable polynomial (the resultant of $x$ and $x'$ is not + close to $0$). + + An integer can be input in factored form as in arithmetic functions. + \bprog + ? issquarefree(factor(6)) + %1 = 1 + \\ count squarefree integers up to 10^8 + ? c = 0; for(d = 1, 10^8, if (issquarefree(d), c++)); c + time = 3min, 2,590 ms. + %2 = 60792694 + ? c = 0; forfactored(d = 1, 10^8, if (issquarefree(d), c++)); c + time = 45,348 ms. \\ faster ! + %3 = 60792694 + @eprog + +Function: istotient +Class: basic +Section: number_theoretical +C-Name: istotient +Prototype: lGD& +Help: istotient(x,{&N}): true(1) if x = eulerphi(n) for some integer n, + false(0) if not. If N is given, set N = n as well. +Doc: true (1) if $x = \phi(n)$ for some integer $n$, false (0) + if not. + \bprog + ? istotient(14) + %1 = 0 + ? istotient(100) + %2 = 0 + @eprog + If $N$ is given, set $N = n$ as well. + \bprog + ? istotient(4, &n) + %1 = 1 + ? n + %2 = 10 + @eprog + +Function: kill +Class: basic +Section: programming/specific +C-Name: kill0 +Prototype: vr +Help: kill(sym): restores the symbol sym to its ``undefined'' status and kill + attached help messages. +Doc: restores the symbol \kbd{sym} to its ``undefined'' status, and deletes any + help messages attached to \kbd{sym} using \kbd{addhelp}. Variable names + remain known to the interpreter and keep their former priority: you cannot + make a variable ``less important" by killing it! + \bprog + ? z = y = 1; y + %1 = 1 + ? kill(y) + ? y \\ restored to ``undefined'' status + %2 = y + ? variable() + %3 = [x, y, z] \\ but the variable name y is still known, with y > z ! + @eprog\noindent + For the same reason, killing a user function (which is an ordinary + variable holding a \typ{CLOSURE}) does not remove its name from the list of + variable names. + + If the symbol is attached to a variable --- user functions being an + important special case ---, one may use the \idx{quote} operator + \kbd{a = 'a} to reset variables to their starting values. However, this + will not delete a help message attached to \kbd{a}, and is also slightly + slower than \kbd{kill(a)}. + \bprog + ? x = 1; addhelp(x, "foo"); x + %1 = 1 + ? x = 'x; x \\ same as 'kill', except we don't delete help. + %2 = x + ? ?x + foo + @eprog\noindent + On the other hand, \kbd{kill} is the only way to remove aliases and installed + functions. + \bprog + ? alias(fun, sin); + ? kill(fun); + + ? install(addii, GG); + ? kill(addii); + @eprog + +Function: kronecker +Class: basic +Section: number_theoretical +C-Name: kronecker +Prototype: lGG +Help: kronecker(x,y): kronecker symbol (x/y). +Description: + (small, small):small kross($1, $2) + (int, small):small krois($1, $2) + (small, int):small krosi($1, $2) + (gen, gen):small kronecker($1, $2) +Doc: + \idx{Kronecker symbol} $(x|y)$, where $x$ and $y$ must be of type integer. By + definition, this is the extension of \idx{Legendre symbol} to $\Z \times \Z$ + by total multiplicativity in both arguments with the following special rules + for $y = 0, -1$ or $2$: + + \item $(x|0) = 1$ if $|x| = 1$ and $0$ otherwise. + + \item $(x|-1) = 1$ if $x \geq 0$ and $-1$ otherwise. + + \item $(x|2) = 0$ if $x$ is even and $1$ if $x = 1,-1 \mod 8$ and $-1$ + if $x=3,-3 \mod 8$. + +Function: lambertw +Class: basic +Section: transcendental +C-Name: glambertW +Prototype: GD0,L,p +Help: lambertw(y,{branch=0}): solution of the implicit equation x*exp(x)=y. + In the p-adic case, give a solution of x*exp(x)=y if y has valuation > 1 + (or p odd and positive valuation), of log(x)+x=log(y) otherwise. +Doc: Lambert $W$ function, solution of the implicit equation $xe^{x}=y$. + + \item For real inputs $y$: + If \kbd{branch = 0}, principal branch $W_{0}$ defined for $y\ge-\exp(-1)$. + If \kbd{branch = -1}, branch $W_{-1}$ defined for $-\exp(-1)\le y<0$. + + \item For $p$-adic inputs, $p$ odd: give a solution of $x\exp(x)=y$ if $y$ has + positive valuation, of $\log(x)+x=\log(y)$ otherwise. + + \item For $2$-adic inputs: give a solution of $x\exp(x)=y$ if $y$ has + valuation $> 1$, of $\log(x)+x=\log(y)$ otherwise. + + \misctitle{Caveat} + Complex values of $y$ are also supported but experimental. The other + branches $W_{k}$ for $k$ not equal to $0$ or $-1$ (set \kbd{branch} to $k$) + are also experimental. + + For $k\ge1$, $W_{-1-k}(x)=\overline{W_{k}(x)}$, and $\Im(W_{k}(x))$ is + close to $(\pi/2)(4k-\text{sign}(x))$. + +Function: laurentseries +Class: basic +Section: sums +C-Name: laurentseries0 +Prototype: GDPDnp +Help: laurentseries(f,{M=seriesprecision},{x='x}): expand f around 0 as a + Laurent series in x to order M. +Doc: Expand $f$ as a Laurent series around $x = 0$ to order $M$. This + function computes $f(x + O(x^{n}))$ until $n$ is large enough: it + must be possible to evaluate $f$ on a power series with $0$ constant term. + \bprog + ? laurentseries(t->sin(t)/(1-cos(t)), 5) + %1 = 2*x^-1 - 1/6*x - 1/360*x^3 - 1/15120*x^5 + O(x^6) + ? laurentseries(log) + *** at top-level: laurentseries(log) + *** ^------------------ + *** in function laurentseries: log + *** ^--- + *** log: domain error in log: series valuation != 0 + @eprog + + Note that individual Laurent coefficients of order $\leq M$ + can be retrieved from $s = \kbd{laurentseries}(f,M)$ via \kbd{polcoef(s,i)} + for any $i \leq M$. The series $s$ may occasionally be more precise that + the required $O(x^{M+1})$. + + With respect to successive calls to \tet{derivnum}, + \kbd{laurentseries} is both faster and more precise: + \bprog + ? laurentseries(t->log(3+t),1) + %1 = 1.0986122886681096913952452369225257047 + 1/3*x - 1/18*x^2 + O(x^3) + ? derivnum(t=0,log(3+t),1) + %2 = 0.33333333333333333333333333333333333333 + ? derivnum(t=0,log(3+t),2) + %3 = -0.11111111111111111111111111111111111111 + + ? f = x->sin(exp(x)); + ? polcoef(laurentseries(x->f(x+2), 1), 1) + %5 = 3.3129294231043339804683687620360224365 + ? exp(2) * cos(exp(2)); + %6 = 3.3129294231043339804683687620360224365 + ? derivnum(x = 2, f(x)) + %7 = 3.3129294231043339804683687620360224364 \\ 1 ulp off + + ? default(realprecision,115); + ? for(i=1,10^4, laurentseries(x->f(x+2),1)) + time = 279 ms. + ? for(i=1,10^4, derivnum(x=2,f(x))) \\ ... and slower + time = 1,134 ms. + @eprog + + \synt{laurentseries}{void *E, GEN (*f)(void*,GEN,long), long M, long v, long prec}. + +Function: lcm +Class: basic +Section: number_theoretical +C-Name: glcm0 +Prototype: GDG +Help: lcm(x,{y}): least common multiple of x and y, i.e. x*y / gcd(x,y) + up to units. +Description: + (int, int):int lcmii($1, $2) + (gen):gen glcm0($1, NULL) + (gen, gen):gen glcm($1, $2) +Doc: least common multiple of $x$ and $y$, i.e.~such + that $\lcm(x,y)*\gcd(x,y) = x*y$, up to units. If $y$ is omitted and $x$ + is a vector, returns the $\text{lcm}$ of all components of $x$. + For integer arguments, return the nonnegative \text{lcm}. + + When $x$ and $y$ are both given and one of them is a vector/matrix type, + the LCM is again taken recursively on each component, but in a different way. + If $y$ is a vector, resp.~matrix, then the result has the same type as $y$, + and components equal to \kbd{lcm(x, y[i])}, resp.~\kbd{lcm(x, y[,i])}. Else + if $x$ is a vector/matrix the result has the same type as $x$ and an + analogous definition. Note that for these types, \kbd{lcm} is not + commutative. + + Note that \kbd{lcm(v)} is quite different from + \bprog + l = v[1]; for (i = 1, #v, l = lcm(l, v[i])) + @eprog\noindent + Indeed, \kbd{lcm(v)} is a scalar, but \kbd{l} may not be (if one of + the \kbd{v[i]} is a vector/matrix). The computation uses a divide-conquer tree + and should be much more efficient, especially when using the GMP + multiprecision kernel (and more subquadratic algorithms become available): + \bprog + ? v = vector(10^5, i, random); + ? lcm(v); + time = 546 ms. + ? l = v[1]; for (i = 1, #v, l = lcm(l, v[i])) + time = 4,561 ms. + @eprog + +Function: length +Class: basic +Section: conversions +C-Name: glength +Prototype: lG +Help: length(x): number of non code words in x, number of characters for a + string. +Description: + (vecsmall):lg lg($1) + (vec):lg lg($1) + (pol):small lgpol($1) + (gen):small glength($1) +Doc: length of $x$; \kbd{\#}$x$ is a shortcut for \kbd{length}$(x)$. + This is mostly useful for + + \item vectors: dimension (0 for empty vectors), + + \item lists: number of entries (0 for empty lists), + + \item maps: number of entries (0 for empty maps), + + \item matrices: number of columns, + + \item character strings: number of actual characters (without + trailing \kbd{\bs 0}, should you expect it from $C$ \kbd{char*}). + \bprog + ? #"a string" + %1 = 8 + ? #[3,2,1] + %2 = 3 + ? #[] + %3 = 0 + ? #matrix(2,5) + %4 = 5 + ? L = List([1,2,3,4]); #L + %5 = 4 + ? M = Map([a,b; c,d; e,f]); #M + %6 = 3 + @eprog + + The routine is in fact defined for arbitrary GP types, but is awkward and + useless in other cases: it returns the number of non-code words in $x$, e.g. + the effective length minus 2 for integers since the \typ{INT} type has two code + words. +Variant: + Also available is \fun{long}{gtranslength}{GEN x} + which return the length of \kbd{x~}, that is the number of lines of matrices. + +Function: lerchphi +Class: basic +Section: transcendental +C-Name: lerchphi +Prototype: GGGp +Help: lerchphi(z,s,a): Lerch transcendent equal to sum for n >= 0 of + z^n / (n+a)^s for reasonable values of the arguments. +Doc: Lerch transcendent $\Phi(z,s,a)=\sum_{n\ge0}z^{n}(n+a)^{-s}$ and + analytically continued, for reasonable values of the arguments. + +Function: lerchzeta +Class: basic +Section: transcendental +C-Name: lerchzeta +Prototype: GGGp +Help: lerchzeta(s,a,lam): Lerch zeta function equal to sum for n >= 0 of + e^(2 pi i lam n) / (n+a)^s for reasonable values of the arguments. +Doc: Lerch zeta function + $$L(s,a,\lambda)=\sum_{n\ge0}e^{2\pi i\lambda n}(n+a)^{-s}$$ + and analytically continued, for reasonable values of the arguments. + +Function: lex +Class: basic +Section: operators +C-Name: lexcmp +Prototype: iGG +Help: lex(x,y): compare x and y lexicographically (1 if x>y, 0 if x=y, -1 if x$ vector $>$ scalar. + For example: + \bprog + ? lex([1,3], [1,2,5]) + %1 = 1 + ? lex([1,3], [1,3,-1]) + %2 = -1 + ? lex([1], [[1]]) + %3 = -1 + ? lex([1], [1]~) + %4 = 0 + ? lex(2 - I, 1) + %5 = 1 + ? lex(2 - I, 2) + %6 = -1 + @eprog + +Function: lfun +Class: basic +Section: l_functions +C-Name: lfun0 +Prototype: GGD0,L,b +Help: lfun(L,s,{D=0}): compute the L-function value L(s), or + if D is set, the derivative of order D at s. L is either an + Lmath, an Ldata or an Linit. +Description: + (gen,gen):gen:prec lfun($1, $2, $bitprec) + (gen,gen,?0):gen:prec lfun($1, $2, $bitprec) + (gen,gen,small):gen:prec lfun0($1, $2, $3, $bitprec) +Doc: compute the L-function value $L(s)$, or if \kbd{D} is set, the + derivative of order \kbd{D} at $s$. The parameter + \kbd{L} is either an Lmath, an Ldata (created by \kbd{lfuncreate}, or an + Linit (created by \kbd{lfuninit}), preferrably the latter if many values + are to be computed. + + The argument $s$ is also allowed to be a power series; for instance, if $s = + \alpha + x + O(x^{n})$, the function returns the Taylor expansion of order $n$ + around $\alpha$. The result is given with absolute error less than $2^{-B}$, + where $B = \text{realbitprecision}$. + + \misctitle{Caveat} The requested precision has a major impact on runtimes. + It is advised to manipulate precision via \tet{realbitprecision} as + explained above instead of \tet{realprecision} as the latter allows less + granularity: \kbd{realprecision} increases by increments of 64 bits, i.e. 19 + decimal digits at a time. + + \bprog + ? lfun(x^2+1, 2) \\ Lmath: Dedekind zeta for Q(i) at 2 + %1 = 1.5067030099229850308865650481820713960 + + ? L = lfuncreate(ellinit("5077a1")); \\ Ldata: Hasse-Weil zeta function + ? lfun(L, 1+x+O(x^4)) \\ zero of order 3 at the central point + %3 = 0.E-58 - 5.[...] E-40*x + 9.[...] E-40*x^2 + 1.7318[...]*x^3 + O(x^4) + + \\ Linit: zeta(1/2+it), |t| < 100, and derivative + ? L = lfuninit(1, [100], 1); + ? T = lfunzeros(L, [1,25]); + %5 = [14.134725[...], 21.022039[...]] + ? z = 1/2 + I*T[1]; + ? abs( lfun(L, z) ) + %7 = 8.7066865533412207420780392991125136196 E-39 + ? abs( lfun(L, z, 1) ) + %8 = 0.79316043335650611601389756527435211412 \\ simple zero + @eprog + +Function: lfunan +Class: basic +Section: l_functions +C-Name: lfunan +Prototype: GLp +Help: lfunan(L,n): compute the first n terms of the Dirichlet series + attached to the L-function given by L (Lmath, Ldata or Linit). +Doc: Compute the first $n$ terms of the Dirichlet series attached to the + $L$-function given by \kbd{L} (\kbd{Lmath}, \kbd{Ldata} or \kbd{Linit}). + \bprog + ? lfunan(1, 10) \\ Riemann zeta + %1 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + ? lfunan(5, 10) \\ Dirichlet L-function for kronecker(5,.) + %2 = [1, -1, -1, 1, 0, 1, -1, -1, 1, 0] + @eprog + +Function: lfunartin +Class: basic +Section: l_functions +C-Name: lfunartin +Prototype: GGGLb +Help: lfunartin(nf,gal,rho,n): returns the Ldata structure attached to the + Artin L-function provided by the representation rho of the Galois group of the + extension K/Q, defined over the cyclotomic field Q(zeta_n), where nf is the + nfinit structure attached to K, gal is the galoisinit structure attached to + K/Q, and rho is given either by the values of its character on the conjugacy + classes or by the matrices that are the images of the generators. Cyclotomic + numbers in rho are represented by polynomials, whose variable is understood as + the complex number exp(2*I*Pi/n). +Doc: returns the \kbd{Ldata} structure attached to the + Artin $L$-function provided by the representation $\rho$ of the Galois group + of the extension $K/\Q$, defined over the cyclotomic field $\Q(\zeta_{n})$, + where \var{nf} is the nfinit structure attached to $K$, + \var{gal} is the galoisinit structure attached to $K/\Q$, and \var{rho} is + given either + + \item by the values of its character on the conjugacy classes + (see \kbd{galoisconjclasses} and \kbd{galoischartable}) + + \item or by the matrices that are the images of the generators + \kbd{\var{gal}.gen}. + + Cyclotomic numbers in \kbd{rho} are represented by polynomials, whose + variable is understood as the complex number $\exp(2\*i\*\pi/n)$. + + In the following example we build the Artin $L$-functions attached to the two + irreducible degree $2$ representations of the dihedral group $D_{10}$ defined + over $\Q(\zeta_{5})$, for the extension $H/\Q$ where $H$ is the Hilbert class + field of $\Q(\sqrt{-47})$. + We show numerically some identities involving Dedekind $\zeta$ functions and + Hecke $L$ series. + \bprog + ? P = quadhilbert(-47) + %1 = x^5 + 2*x^4 + 2*x^3 + x^2 - 1 + ? N = nfinit(nfsplitting(P)); + ? G = galoisinit(N); \\ D_10 + ? [T,n] = galoischartable(G); + ? T \\ columns give the irreducible characters + %5 = + [1 1 2 2] + + [1 -1 0 0] + + [1 1 -y^3 - y^2 - 1 y^3 + y^2] + + [1 1 y^3 + y^2 -y^3 - y^2 - 1] + ? n + %6 = 5 + ? L2 = lfunartin(N,G, T[,2], n); + ? L3 = lfunartin(N,G, T[,3], n); + ? L4 = lfunartin(N,G, T[,4], n); + ? s = 1 + x + O(x^4); + ? lfun(-47,s) - lfun(L2,s) + %11 ~ 0 + ? lfun(1,s)*lfun(-47,s)*lfun(L3,s)^2*lfun(L4,s)^2 - lfun(N,s) + %12 ~ 0 + ? lfun(1,s)*lfun(L3,s)*lfun(L4,s) - lfun(P,s) + %13 ~ 0 + ? bnr = bnrinit(bnfinit(x^2+47),1,1); + ? bnr.cyc + %15 = [5] \\ Z/5Z: 4 nontrivial ray class characters + ? lfun([bnr,[1]], s) - lfun(L3, s) + %16 ~ 0 + ? lfun([bnr,[2]], s) - lfun(L4, s) + %17 ~ 0 + ? lfun([bnr,[3]], s) - lfun(L3, s) + %18 ~ 0 + ? lfun([bnr,[4]], s) - lfun(L4, s) + %19 ~ 0 + @eprog + The first identity identifies the nontrivial abelian character with + $(-47,\cdot)$; the second is the factorization of the regular representation of + $D_{10}$; the third is the factorization of the natural representation of + $D_{10}\subset S_{5}$; and the final four are the expressions of the degree $2$ + representations as induced from degree $1$ representations. + +Function: lfuncheckfeq +Class: basic +Section: l_functions +C-Name: lfuncheckfeq +Prototype: lGDGb +Help: lfuncheckfeq(L,{t}): given an L-function (Lmath, Ldata or Linit), + check whether the functional equation is satisfied. If the function has + poles, the polar part must be specified. The program returns a bit accuracy + which should be a large negative value close to the current bit accuracy. + If t is given, it checks the functional equation for the theta function + at t and 1/t. +Doc: Given the data attached to an $L$-function (\kbd{Lmath}, \kbd{Ldata} + or \kbd{Linit}), check whether the functional equation is satisfied. + This is most useful for an \kbd{Ldata} constructed ``by hand'', via + \kbd{lfuncreate}, to detect mistakes. + + If the function has poles, the polar part must be specified. The routine + returns a bit accuracy $b$ such that $|w - \hat{w}| < 2^{b}$, where $w$ is + the root number contained in \kbd{data}, and + $$\hat{w} = \theta(1/t) t^{-k} / \overline{\theta}(t)$$ is a computed value + derived from the assumed functional equation. + Of course, the expected result is a large negative value of the order of + \kbd{realbitprecision}. But if $\overline{\theta}$ is very small + at $t$, you should first increase \kbd{realbitprecision} by + $-\log_{2} |\overline{\theta}(t)|$, which is + positive if $\theta$ is small, to get a meaningful result. + Note that $t$ should be close to the unit disc for efficiency and such that + $\overline{\theta}(t) \neq 0$. If the parameter $t$ is omitted, we check the + functional equation at the ``random'' complex number $t = 335/339 + I/7$. + \bprog + ? \pb 128 \\ 128 bits of accuracy + ? default(realbitprecision) + %1 = 128 + ? L = lfuncreate(1); \\ Riemann zeta + ? lfuncheckfeq(L) + %3 = -124 + @eprog\noindent i.e. the given data is consistent to within 4 bits for the + particular check consisting of estimating the root number from all other + given quantities. Checking away from the unit disc will either fail with + a precision error, or give disappointing results (if $\theta(1/t)$ is + large it will be computed with a large absolute error) + \bprog + ? lfuncheckfeq(L, 2+I) + %4 = -115 + ? lfuncheckfeq(L,10) + *** at top-level: lfuncheckfeq(L,10) + *** ^------------------ + *** lfuncheckfeq: precision too low in lfuncheckfeq. + @eprog + \misctitle{The case of Dedekind zeta functions} Dedekind zeta function for + a number field $K = \Q[X]/(T)$ is in general computed + (assuming Artin conjecture) as $(\zeta_{K}/\zeta_{k}) \times \zeta_{k}$, + where $k$ is a + maximal subfield, applied recursively if possible. When $K/\Q$ is Galois, + the zeta function is directly decomposed as a product of Artin + $L$-functions. + + These decompositions are computed when \kbd{lfuninit} is called. The + behavior of \kbd{lfuncheckfeq} is then different depending of its argument + + \item the artificial query \kbd{lfuncheckfeq}$(T)$ serves little purpose + since we already know that the technical parameters are theoretically + correct; we just obtain an estimate on the accuracy they allow. This is + computed directly, without using the above decomposition. And is likely to + be very costly if the degree of $T$ is large, possibly overflowing the + possibilities of the implementation. + + \item a query \kbd{L = lfuninit(T, ...); lfuncheckfeq(L)} on the other hand + returns the maximum of the \kbd{lfuncheckfeq} values for all involved + $L$-functions, giving a general consistency check and again an estimate + for the accuracy of computed values. + + At the default accuracy of 128 bits: + \bprog + ? T = polcyclo(43); + ? lfuncheckfeq(T); + *** at top-level: lfuncheckfeq(T) + *** ^--------------- + *** lfuncheckfeq: overflow in lfunthetacost. + ? lfuncheckfeq(lfuninit(T, [2])) + time = 107 ms. + %2 = -122 + @eprog + +Function: lfunconductor +Class: basic +Section: l_functions +C-Name: lfunconductor +Prototype: GDGD0,L,b +Help: lfunconductor(L,{setN=10000},{flag=0}): gives the conductor + of the given L-function, expecting to find it in the interval [1,setN]. + If flag=0 (default), gives either the conductor found as an integer, or a + vector of conductors found, possibly empty. If flag=1, same but gives the + computed floating point approximations to the conductors found, without + rounding to integers. If flag=2, gives all the conductors found, even those + far from integers. Alternatively, setN can contain a list of possible + conductors and we select the best one according to lfuncheckfeq; + in this case, flag is ignored and we return [N, lfuncheckfeq for that N]. +Doc: Computes the conductor of the given $L$-function (if the structure + contains a conductor, it is ignored). Two methods are available, + depending on what we know about the conductor, encoded in the \kbd{setN} + parameter: + + \item \kbd{setN} is a scalar: we know nothing but expect that the conductor + lies in the interval $[1, \kbd{setN}]$. + + If $\fl$ is $0$ (default), gives either the conductor found as an + integer, or a vector (possibly empty) of conductors found. If $\fl$ is + $1$, same but gives the computed floating point approximations to the + conductors found, without rounding to integers. It $\fl$ is $2$, gives + all the conductors found, even those far from integers. + + \misctitle{Caveat} This is a heuristic program and the result is not + proven in any way: + \bprog + ? L = lfuncreate(857); \\ Dirichlet L function for kronecker(857,.) + ? \p19 + realprecision = 19 significant digits + ? lfunconductor(L) + %2 = [17, 857] + ? lfunconductor(L,,1) \\ don't round + %3 = [16.99999999999999999, 857.0000000000000000] + + ? \p38 + realprecision = 38 significant digits + ? lfunconductor(L) + %4 = 857 + @eprog\noindent Increasing \kbd{setN} or increasing \kbd{realbitprecision} + slows down the program but gives better accuracy for the result. This + algorithm should only be used if the primes dividing the conductor are + unknown, which is uncommon. + + \item \kbd{setN} is a vector of possible conductors; for instance + of the form \kbd{D1 * divisors(D2)}, where $D_{1}$ is the known part + of the conductor and $D_{2}$ is a multiple of the contribution of the + bad primes. + + In that case, $\fl$ is ignored and the routine uses \kbd{lfuncheckfeq}. + It returns $[N,e]$ where $N$ is the best conductor in the list and $e$ is the + value of \kbd{lfuncheckfeq} for that $N$. When no suitable conductor exist or + there is a tie among best potential conductors, return the empty vector + \kbd{[]}. + \bprog + ? E = ellinit([0,0,0,4,0]); /* Elliptic curve y^2 = x^3+4x */ + ? E.disc \\ |disc E| = 2^12 + %2 = -4096 + \\ create Ldata by hand. Guess that root number is 1 and conductor N + ? L(N) = lfuncreate([n->ellan(E,n), 0, [0,1], 2, N, 1]); + \\ lfunconductor ignores conductor = 1 in Ldata ! + ? lfunconductor(L(1), divisors(E.disc)) + %5 = [32, -127] + ? fordiv(E.disc, d, print(d,": ",lfuncheckfeq(L(d)))) \\ direct check + 1: 0 + 2: 0 + 4: -1 + 8: -2 + 16: -3 + 32: -127 + 64: -3 + 128: -2 + 256: -2 + 512: -1 + 1024: -1 + 2048: 0 + 4096: 0 + @eprog\noindent The above code assumed that root number was $1$; + had we set it to $-1$, none of the \kbd{lfuncheckfeq} values would have been + acceptable: + \bprog + ? L2 = lfuncreate([n->ellan(E,n), 0, [0,1], 2, 0, -1]); + ? lfunconductor(L2, divisors(E.disc)) + %7 = [] + @eprog + +Function: lfuncost +Class: basic +Section: l_functions +C-Name: lfuncost0 +Prototype: GDGD0,L,b +Help: lfuncost(L,{sdom},{der=0}): estimate the cost of running + lfuninit(L,sdom,der) at current bit precision. Returns [t,b], to indicate + that t coefficients a_n will be computed at bit accuracy b. Subsequent + evaluation of lfun at s evaluates a polynomial of degree t at exp(h s). + If L is already an Linit, then sdom and der are ignored. +Doc: estimate the cost of running + \kbd{lfuninit(L,sdom,der)} at current bit precision, given by a vector + $[t, b]$. + + \item If $L$ contains the root number, indicate that $t$ coefficients $a_{n}$ + will be computed, as well as $t$ values of \tet{gammamellininv}, all at bit + accuracy $b$. A subsequent call to \kbd{lfun} at $s$ evaluates a polynomial + of degree $t$ at $\exp(h s)$ for some real parameter $h$, at the same bit + accuracy $b$. + + \item If the root number is \emph{not} known, then more values of $a_{n}$ may + be needed in order to compute it, and the returned value of $t$ takes this + into account (it may not be the exact value in this case but is always + an upper bound). Fewer than $t$ \kbd{gammamellininv} will be needed, and + a call to \kbd{lfun} evaluates a polynomial of degree less that $t$, still + at bit accuracy $b$. + + If $L$ is already an \kbd{Linit}, then \var{sdom} and \var{der} are ignored + and are best left omitted; the bit accuracy is also inferred from $L$: in + short we get an estimate of the cost of using that particular \kbd{Linit}. + Note that in this case, the root number is always already known and you get + the right value of $t$ (corresponding to the number of past calls to + \kbd{gammamellinv} and the actual degree of the evaluated polynomial). + + \bprog + ? \pb 128 + ? lfuncost(1, [100]) \\ for zeta(1/2+I*t), |t| < 100 + %1 = [7, 242] \\ 7 coefficients, 242 bits + ? lfuncost(1, [1/2, 100]) \\ for zeta(s) in the critical strip, |Im s| < 100 + %2 = [7, 246] \\ now 246 bits + ? lfuncost(1, [100], 10) \\ for zeta(1/2+I*t), |t| < 100 + %3 = [8, 263] \\ 10th derivative increases the cost by a small amount + ? lfuncost(1, [10^5]) + %3 = [158, 113438] \\ larger imaginary part: huge accuracy increase + + ? L = lfuncreate(polcyclo(5)); \\ Dedekind zeta for Q(zeta_5) + ? lfuncost(L, [100]) \\ at s = 1/2+I*t), |t| < 100 + %5 = [11457, 582] + ? lfuncost(L, [200]) \\ twice higher + %6 = [36294, 1035] + ? lfuncost(L, [10^4]) \\ much higher: very costly ! + %7 = [70256473, 45452] + ? \pb 256 + ? lfuncost(L, [100]); \\ doubling bit accuracy is cheaper + %8 = [17080, 710] + + ? \p38 + ? K = bnfinit(y^2 - 4493); [P] = idealprimedec(K,1123); f = [P,[1,1]]; + ? R = bnrinit(K, f); R.cyc + %10 = [1122] + ? L = lfuncreate([R, [7]]); \\ Hecke L-function + ? L[6] + %12 = 0 \\ unknown root number + ? \pb 3000 + ? lfuncost(L, [0], 1) + %13 = [1171561, 3339] + ? L = lfuninit(L, [0], 1); + time = 1min, 56,426 ms. + ? lfuncost(L) + %14 = [826966, 3339] + @eprog\noindent In the final example, the root number was unknown and + extra coefficients $a_{n}$ were needed to compute it ($1171561$). Once the + initialization is performed we obtain the lower value $t = 826966$, which + corresponds to the number of \kbd{gammamellinv} computed and the actual + degree of the polynomial to be evaluated to compute a value within the + prescribed domain. + + Finally, some $L$ functions can be factorized algebraically + by the \kbd{lfuninit} call, e.g. the Dedekind zeta function of abelian + fields, leading to much faster evaluations than the above upper bounds. + In that case, the function returns a vector of costs as above for each + individual function in the product actually evaluated: + \bprog + ? L = lfuncreate(polcyclo(5)); \\ Dedekind zeta for Q(zeta_5) + ? lfuncost(L, [100]) \\ a priori cost + %2 = [11457, 582] + ? L = lfuninit(L, [100]); \\ actually perform all initializations + ? lfuncost(L) + %4 = [[16, 242], [16, 242], [7, 242]] + @eprog\noindent The Dedekind function of this abelian quartic field + is the product of four Dirichlet $L$-functions attached to the trivial + character, a nontrivial real character and two complex conjugate + characters. The nontrivial characters happen to have the same conductor + (hence same evaluation costs), and correspond to two evaluations only + since the two conjugate characters are evaluated simultaneously. + For a total of three $L$-functions evaluations, which explains the three + components above. Note that the actual cost is much lower than the a priori + cost in this case. +Variant: Also available is + \fun{GEN}{lfuncost}{GEN L, GEN dom, long der, long bitprec} + when $L$ is \emph{not} an \kbd{Linit}; the return value is a \typ{VECSMALL} + in this case. + +Function: lfuncreate +Class: basic +Section: l_functions +C-Name: lfuncreate +Prototype: G +Help: lfuncreate(obj): given either an object such as a polynomial, elliptic + curve, Dirichlet or Hecke character, eta quotient, etc., or an explicit + 6 or 7 component vector [dir,real,Vga,k,N,eps,r], + create the Ldata structure necessary for lfun computation. +Doc: This low-level routine creates \tet{Ldata} structures, needed by + \var{lfun} functions, describing an $L$-function and its functional equation. + We advise using a high-level constructor when one is available, see + \kbd{??lfun}, and this function accepts them: + \bprog + ? L = lfuncreate(1); \\ Riemann zeta + ? L = lfuncreate(5); \\ Dirichlet L-function for quadratic character (5/.) + ? L = lfuncreate(x^2+1); \\ Dedekind zeta for Q(i) + ? L = lfuncreate(ellinit([0,1])); \\ L-function of E/Q: y^2=x^3+1 + @eprog\noindent One can then use, e.g., \kbd{lfun(L,s)} to directly + evaluate the respective $L$-functions at $s$, or \kbd{lfuninit(L, [c,w,h]} + to initialize computations in the rectangular box $\Re(s-c) \leq w$, + $\Im(s) \leq h$. + + We now describe the low-level interface, used to input nonbuiltin + $L$-functions. The input is now a $6$ or $7$ component vector + $V=[a, astar, Vga, k, N, eps, poles]$, whose components are as follows: + + \item \kbd{V[1]=a} encodes the Dirichlet series coefficients $(a_{n})$. The + preferred format is a closure of arity 1: \kbd{n->vector(n,i,a(i))} giving + the vector of the first $n$ coefficients. The closure is allowed to return + a vector of more than $n$ coefficients (only the first $n$ will be + considered) or even less than $n$, in which case loss of accuracy will occur + and a warning that \kbd{\#an} is less than expected is issued. This + allows to precompute and store a fixed large number of Dirichlet + coefficients in a vector $v$ and use the closure \kbd{n->v}, which + does not depend on $n$. As a shorthand for this latter case, you can input + the vector $v$ itself instead of the closure. + \bprog + ? z = lfuncreate([n->vector(n,i,1), 1, [0], 1, 1, 1, 1]); \\ Riemann zeta + ? lfun(z,2) - Pi^2/6 + %2 = -5.877471754111437540 E-39 + @eprog + + A second format is limited to $L$-functions affording an + Euler product. It is a closure of arity 2 \kbd{(p,d)->F(p)} giving the + local factor $L_{p}(X)$ at $p$ as a rational function, to be evaluated at + $p^{-s}$ as in \kbd{direuler}; $d$ is set to \kbd{logint}$(n,p)$ + 1, where + $n$ is the total number of Dirichlet coefficients $(a_{1},\dots,a_{n})$ that will + be computed. In other words, the smallest integer $d$ such that $p^{d} > n$. + This parameter $d$ allows to compute only part of + $L_{p}$ when $p$ is large and $L_{p}$ expensive to compute: any polynomial + (or \typ{SER}) congruent to $L_{p}$ modulo $X^{d}$ is acceptable since only + the coefficients of $X^{0}, \dots, X^{d-1}$ are needed to expand the Dirichlet + series. The closure can of course ignore this parameter: + + \bprog + ? z = lfuncreate([(p,d)->1/(1-x), 1, [0], 1, 1, 1, 1]); \\ Riemann zeta + ? lfun(z,2) - Pi^2/6 + %4 = -5.877471754111437540 E-39 + @eprog\noindent + One can describe separately the generic local factors coefficients + and the bad local factors by setting $\kbd{dir} = [F, L_{bad}]$, + were $L_{bad} = [[p_{1},L_{p_{1}}], \dots,[p_{k},L_{p_{k}}]]$, where $F$ + describes the generic local factors as above, except that when $p = p_{i}$ + for some $i \leq k$, the coefficient $a_{p}$ is directly set to $L_{p_{i}}$ + instead of calling $F$. + + \bprog + N = 15; + E = ellinit([1, 1, 1, -10, -10]); \\ = "15a1" + F(p,d) = 1 / (1 - ellap(E,p)*'x + p*'x^2); + Lbad = [[3, 1/(1+'x)], [5, 1/(1-'x)]]; + L = lfuncreate([[F,Lbad], 0, [0,1], 2, N, ellrootno(E)]); + @eprog\noindent Of course, in this case, \kbd{lfuncreate(E)} is preferable! + + \item \kbd{V[2]=astar} is the Dirichlet series coefficients of the dual + function, encoded as \kbd{a} above. The sentinel values $0$ and $1$ may + be used for the special cases where $a = a^{*}$ and $a = \overline{a^{*}}$, + respectively. + + \item \kbd{V[3]=Vga} is the vector of $\alpha_{j}$ such that the gamma + factor of the $L$-function is equal to + $$\gamma_{A}(s)=\prod_{1\le j\le d}\Gamma_{\R}(s+\alpha_{j}),$$ + where $\Gamma_{\R}(s)=\pi^{-s/2}\Gamma(s/2)$. + This same syntax is used in the \kbd{gammamellininv} functions. + In particular the length $d$ of \kbd{Vga} is the degree of the $L$-function. + In the present implementation, the $\alpha_{j}$ are assumed to be exact + rational numbers. However when calling theta functions with \emph{complex} + (as opposed to real) arguments, determination problems occur which may + give wrong results when the $\alpha_{j}$ are not integral. + + \item \kbd{V[4]=k} is a positive integer $k$. The functional equation relates + values at $s$ and $k-s$. For instance, for an Artin $L$-series such as a + Dedekind zeta function we have $k = 1$, for an elliptic curve $k = 2$, and + for a modular form, $k$ is its weight. For motivic $L$-functions, the + \emph{motivic} weight $w$ is $w = k-1$. + + By default we assume that $a_{n} = O_{\epsilon}(n^{k_{1}+\epsilon})$, where + $k_{1} = w$ and even $k_{1} = w/2$ when the $L$ function has no pole + (Ramanujan-Petersson). If this is not the case, you can replace the + $k$ argument by a vector $[k,k_{1}]$, where $k_{1}$ is the upper bound you can + assume. + + \item \kbd{V[5]=N} is the conductor, an integer $N\ge1$, such that + $\Lambda(s)=N^{s/2}\gamma_{A}(s)L(s)$ with $\gamma_{A}(s)$ as above. + + \item \kbd{V[6]=eps} is the root number $\varepsilon$, i.e., the + complex number (usually of modulus $1$) such that + $\Lambda(a, k-s) = \varepsilon \Lambda(a^{*}, s)$. + + \item The last optional component \kbd{V[7]=poles} encodes the poles of the + $L$ or $\Lambda$-functions, and is omitted if they have no poles. + A polar part is given by a list of $2$-component vectors + $[\beta,P_{\beta}(x)]$, where + $\beta$ is a pole and the power series $P_{\beta}(x)$ describes + the attached polar part, such that $L(s) - P_{\beta}(s-\beta)$ is holomorphic + in a neighbourhood of $\beta$. For instance $P_{\beta} = r/x+O(1)$ for a + simple pole at $\beta$ or $r_{1}/x^{2}+r_{2}/x+O(1)$ for a double pole. + The type of the list describing the polar part allows to distinguish between + $L$ and $\Lambda$: a \typ{VEC} is attached to $L$, and a \typ{COL} + is attached to $\Lambda$. Unless $a = \overline{a^{*}}$ (coded by \kbd{astar} + equal to $0$ or $1$), it is mandatory to specify the polar part of $\Lambda$ + rather than those of $L$ since the poles of $L^{*}$ cannot be infered from the + latter ! Whereas the functional equation allows to deduce the polar part of + $\Lambda^{*}$ from the polar part of $\Lambda$. + + Finally, if $a = \overline{a^{*}}$, we allow a shortcut to describe + the frequent situation where $L$ has at most simple pole, at $s = k$, + with residue $r$ a complex scalar: you may then input $\kbd{poles} = r$. + This value $r$ can be set to $0$ if unknown and it will be computed. + + \misctitle{When one component is not exact} + Alternatively, \kbd{obj} can be a closure of arity $0$ returning the above + vector to the current real precision. This is needed if some components + are not available exactly but only through floating point approximations. + The closure allows algorithms to recompute them to higher accuracy when + needed. Compare + \bprog + ? Ld1() = [n->lfunan(Mod(2,7),n),1,[0],1,7,((-13-3*sqrt(-3))/14)^(1/6)]; + ? Ld2 = [n->lfunan(Mod(2,7),n),1,[0],1,7,((-13-3*sqrt(-3))/14)^(1/6)]; + ? L1 = lfuncreate(Ld1); + ? L2 = lfuncreate(Ld2); + ? lfun(L1,1/2+I*200) \\ OK + %5 = 0.55943925130316677665287870224047183265 - + 0.42492662223174071305478563967365980756*I + ? lfun(L2,1/2+I*200) \\ all accuracy lost + %6 = 0.E-38 + 0.E-38*I + @eprog\noindent + The accuracy lost in \kbd{Ld2} is due to the root number being given to + an insufficient precision. To see what happens try + \bprog + ? Ld3() = printf("prec needed: %ld bits",getlocalbitprec());Ld1() + ? L3 = lfuncreate(Ld3); + prec needed: 64 bits + ? z3 = lfun(L3,1/2+I*200) + prec needed: 384 bits + %16 = 0.55943925130316677665287870224047183265 - + 0.42492662223174071305478563967365980756*I + @eprog + +Function: lfundiv +Class: basic +Section: l_functions +C-Name: lfundiv +Prototype: GGb +Help: lfundiv(L1,L2): creates the Ldata structure (without + initialization) corresponding to the quotient of the Dirichlet series + given by L1 and L2. +Doc: creates the \kbd{Ldata} structure (without initialization) corresponding + to the quotient of the Dirichlet series $L_{1}$ and $L_{2}$ given by + \kbd{L1} and \kbd{L2}. Assume that $v_{z}(L_{1}) \geq v_{z}(L_{2})$ at all + complex numbers $z$: the construction may not create new poles, nor increase + the order of existing ones. + +Function: lfundual +Class: basic +Section: l_functions +C-Name: lfundual +Prototype: Gb +Help: lfundual(L): creates the Ldata structure (without + initialization) corresponding to the dual L-function of L. +Doc: creates the \kbd{Ldata} structure (without initialization) corresponding + to the dual L-function $\hat{L}$ of $L$. If $k$ and $\varepsilon$ are + respectively the weight and root number of $L$, then the following formula + holds outside poles, up to numerical errors: + $$\Lambda(L, s) = \varepsilon \Lambda(\hat{L}, k - s).$$ + + \bprog + ? L = lfunqf(matdiagonal([1,2,3,4])); + ? eps = lfunrootres(L)[3]; k = L[4]; + ? M = lfundual(L); lfuncheckfeq(M) + %3 = -127 + ? s= 1+Pi*I; + ? a = lfunlambda(L,s); + ? b = eps * lfunlambda(M,k-s); + ? exponent(a - b) + %7 = -130 + @eprog + +Function: lfunetaquo +Class: basic +Section: l_functions +C-Name: lfunetaquo +Prototype: G +Help: lfunetaquo(M): returns the Ldata structure attached to the + modular form z->prod(i=1,#M[,1],eta(M[i,1]*z)^M[i,2]). +Doc: returns the \kbd{Ldata} structure attached to the $L$ function + attached to the modular form + $z\mapsto \prod_{i=1}^{n} \eta(M_{i,1}\*z)^{M_{i,2}}$ + It is currently assumed that $f$ is a self-dual cuspidal form on + $\Gamma_{0}(N)$ for some $N$. + For instance, the $L$-function $\sum \tau(n) n^{-s}$ + attached to Ramanujan's $\Delta$ function is encoded as follows + \bprog + ? L = lfunetaquo(Mat([1,24])); + ? lfunan(L, 100) \\ first 100 values of tau(n) + @eprog\noindent For convenience, a \typ{VEC} is also accepted instead of + a factorization matrix with a single row: + \bprog + ? L = lfunetaquo([1,24]); \\ same as above + @eprog + +Function: lfuneuler +Class: basic +Section: l_functions +C-Name: lfuneuler +Prototype: GGp +Help: lfuneuler(L,p): return the Euler factor at p + of the L-function given by L (Lmath, Ldata or Linit) assuming the L-function + admits an Euler product factorization and that it can be determined. +Doc: return the Euler factor at $p$ of the + $L$-function given by \kbd{L} (\kbd{Lmath}, \kbd{Ldata} or \kbd{Linit}), + assuming the $L$-function admits an Euler product factorization and that it + can be determined. + \bprog + ? E=ellinit([1,3]); + ? lfuneuler(E,7) + %2 = 1/(7*x^2-2*x+1) + ? L=lfunsympow(E,2); + ? lfuneuler(L,11) + %4 = 1/(-1331*x^3+275*x^2-25*x+1) + @eprog + +Function: lfungenus2 +Class: basic +Section: l_functions +C-Name: lfungenus2 +Prototype: G +Help: lfungenus2(F): returns the Ldata structure attached to the + L-function attached to the genus-2 curve defined by y^2=F(x) + or y^2+Q(x)*y=P(x) if F=[P,Q]. + Currently, only odd conductors are supported. +Doc: returns the \kbd{Ldata} structure attached to the $L$ function + attached to the genus-2 curve defined by $y^{2}=F(x)$ or + $y^{2}+Q(x)\*y=P(x)$ if $F=[P,Q]$. + Currently, if the conductor is even, its valuation at $2$ might be incorrect + (a warning is issued). + +Function: lfunhardy +Class: basic +Section: l_functions +C-Name: lfunhardy +Prototype: GGb +Help: lfunhardy(L,t): variant of the Hardy L-function attached to L, used for + plotting on the critical line. +Doc: Variant of the Hardy $Z$-function given by \kbd{L}, used for + plotting or locating zeros of $L(k/2+it)$ on the critical line. + The precise definition is as + follows: let $k/2$ be the center of the critical strip, $d$ be the + degree, $\kbd{Vga} = (\alpha_{j})_{j\leq d}$ given the gamma factors, + and $\varepsilon$ be the root number; we set + $s = k/2+it = \rho e^{i\theta}$ and + $2E = d(k/2-1) + \Re(\sum_{1\le j\le d}\alpha_{j})$. Assume first that + $\Lambda$ is self-dual, then the computed function at $t$ is equal to + $$Z(t) = \varepsilon^{-1/2}\Lambda(s) \cdot \rho^{-E}e^{dt\theta/2}\;,$$ + which is a real function of $t$ + vanishing exactly when $L(k/2+it)$ does on the critical line. The + normalizing factor $|s|^{-E}e^{dt\theta/2}$ compensates the + exponential decrease of $\gamma_{A}(s)$ as $t\to\infty$ so that + $Z(t) \approx 1$. For non-self-dual $\Lambda$, the definition is the same + except we drop the $\varepsilon^{-1/2}$ term (which is not well defined since + it depends on the chosen dual sequence $a^{*}(n)$): $Z(t)$ is still of the + order of $1$ and still vanishes where $L(k/2+it)$ does, but it needs no + longer be real-valued. + + \bprog + ? T = 100; \\ maximal height + ? L = lfuninit(1, [T]); \\ initialize for zeta(1/2+it), |t|= 1 + %1 = 15 + ? lfunthetacost(L, 1 + I); \\ cost for theta(1+I). Domain error ! + *** at top-level: lfunthetacost(1,1+I) + *** ^-------------------- + *** lfunthetacost: domain error in lfunthetaneed: arg t > 0.785 + ? lfunthetacost(L, 1 + I/2) \\ for theta(1+I/2). + %2 = 23 + ? lfunthetacost(L, 1 + I/2, 10) \\ for theta^((10))(1+I/2). + %3 = 24 + ? lfunthetacost(L, [2, 1/10]) \\ cost for theta(t), |t| >= 2, |arg(t)| < 1/10 + %4 = 8 + + ? L = lfuncreate( ellinit([1,1]) ); + ? lfunthetacost(L) \\ for t >= 1 + %6 = 2471 + @eprog + +Function: lfunthetainit +Class: basic +Section: l_functions +C-Name: lfunthetainit +Prototype: GDGD0,L,b +Help: lfunthetainit(L,{tdom},{m=0}): precompute data for evaluating + the m-th derivative of theta functions with argument in domain tdom + (by default t is real >= 1). +Doc: Initalization function for evaluating the $m$-th derivative of theta + functions with argument $t$ in domain \var{tdom}. By default (\var{tdom} + omitted), $t$ is real, $t \geq 1$. Otherwise, \var{tdom} may be + + \item a positive real scalar $\rho$: $t$ is real, $t \geq \rho$. + + \item a nonreal complex number: compute at this particular $t$; this + allows to compute $\theta(z)$ for any complex $z$ satisfying $|z|\geq |t|$ + and $|\arg z| \leq |\arg t|$; we must have $|2 \arg z / d| < \pi/2$, where + $d$ is the degree of the $\Gamma$ factor. + + \item a pair $[\rho,\alpha]$: assume that $|t| \geq \rho$ and $|\arg t| \leq + \alpha$; we must have $|2\alpha / d| < \pi/2$, where $d$ is the degree of + the $\Gamma$ factor. + + \bprog + ? \p500 + ? L = lfuncreate(1); \\ Riemann zeta + ? t = 1+I/2; + ? lfuntheta(L, t); \\ direct computation + time = 30 ms. + ? T = lfunthetainit(L, 1+I/2); + time = 30 ms. + ? lfuntheta(T, t); \\ instantaneous + @eprog\noindent The $T$ structure would allow to quickly compute $\theta(z)$ + for any $z$ in the cone delimited by $t$ as explained above. On the other hand + \bprog + ? lfuntheta(T,I) + *** at top-level: lfuntheta(T,I) + *** ^-------------- + *** lfuntheta: domain error in lfunthetaneed: arg t > 0.785398163397448 + @eprog + The initialization is equivalent to + \bprog + ? lfunthetainit(L, [abs(t), arg(t)]) + @eprog + +Function: lfuntwist +Class: basic +Section: l_functions +C-Name: lfuntwist +Prototype: GGb +Help: lfuntwist(L,chi): creates the Ldata structure (without + initialization) corresponding to the twist of L by the primitive character + attached to the Dirichlet L-function chi. This requires that the conductor + of the character is coprime to the conductor of the L-function L. +Doc: creates the Ldata structure (without initialization) corresponding to the + twist of L by the primitive character attached to the Dirichlet character + \kbd{chi}. The conductor of the character must be coprime to the conductor + of the L-function $L$. + +Function: lfunzeros +Class: basic +Section: l_functions +C-Name: lfunzeros +Prototype: GGD8,L,b +Help: lfunzeros(L,lim,{divz=8}): lim being + either an upper limit or a real interval, computes an ordered list of + zeros of L(s) on the critical line up to the given upper limit or in the + given interval. Use a naive algorithm which may miss some zeros. + To use a finer search mesh, set divz to some integral value + larger than the default (= 8). +Doc: \kbd{lim} being either a positive upper limit or a nonempty real + interval, computes an ordered list of zeros of $L(s)$ on the critical line up + to the given upper limit or in the given interval. Use a naive algorithm + which may miss some zeros: it assumes that two consecutive zeros at height + $T \geq 1$ differ at least by $2\pi/\omega$, where + $$\omega := \kbd{divz} \cdot + \big(d\log(T/2\pi) + d+ 2\log(N/(\pi/2)^{d})\big).$$ + To use a finer search mesh, set divz to some integral value + larger than the default (= 8). + \bprog + ? lfunzeros(1, 30) \\ zeros of Rieman zeta up to height 30 + %1 = [14.134[...], 21.022[...], 25.010[...]] + ? #lfunzeros(1, [100,110]) \\ count zeros with 100 <= Im(s) <= 110 + %2 = 4 + @eprog\noindent The algorithm also assumes that all zeros are simple except + possibly on the real axis at $s = k/2$ and that there are no poles in the + search interval. (The possible zero at $s = k/2$ is repeated according to + its multiplicity.) + + If you pass an \kbd{Linit} to the function, the algorithm assumes that a + multiple zero at $s = k / 2$ has order less than or equal to the maximal + derivation order allowed by the \kbd{Linit}. You may increase that value in + the \kbd{Linit} but this is costly: only do it for zeros of low height or in + \kbd{lfunorderzero} instead. + +Function: lift +Class: basic +Section: conversions +C-Name: lift0 +Prototype: GDn +Help: lift(x,{v}): + if v is omitted, lifts elements of Z/nZ to Z, of Qp to Q, and of K[x]/(P) to + K[x]. Otherwise lift only polmods with main variable v. +Description: + (pol):pol lift($1) + (vec):vec lift($1) + (gen):gen lift($1) + (pol, var):pol lift0($1, $2) + (vec, var):vec lift0($1, $2) + (gen, var):gen lift0($1, $2) +Doc: + if $v$ is omitted, lifts intmods from $\Z/n\Z$ in $\Z$, + $p$-adics from $\Q_{p}$ to $\Q$ (as \tet{truncate}), and polmods to + polynomials. Otherwise, lifts only polmods whose modulus has main + variable~$v$. \typ{FFELT} are not lifted, nor are List elements: you may + convert the latter to vectors first, or use \kbd{apply(lift,L)}. More + generally, components for which such lifts are meaningless (e.g. character + strings) are copied verbatim. + \bprog + ? lift(Mod(5,3)) + %1 = 2 + ? lift(3 + O(3^9)) + %2 = 3 + ? lift(Mod(x,x^2+1)) + %3 = x + ? lift(Mod(x,x^2+1)) + %4 = x + @eprog + Lifts are performed recursively on an object components, but only + by \emph{one level}: once a \typ{POLMOD} is lifted, the components of + the result are \emph{not} lifted further. + \bprog + ? lift(x * Mod(1,3) + Mod(2,3)) + %4 = x + 2 + ? lift(x * Mod(y,y^2+1) + Mod(2,3)) + %5 = y*x + Mod(2, 3) \\@com do you understand this one? + ? lift(x * Mod(y,y^2+1) + Mod(2,3), 'x) + %6 = Mod(y, y^2 + 1)*x + Mod(Mod(2, 3), y^2 + 1) + ? lift(%, y) + %7 = y*x + Mod(2, 3) + @eprog\noindent To recursively lift all components not only by one level, + but as long as possible, use \kbd{liftall}. To lift only \typ{INTMOD}s and + \typ{PADIC}s components, use \tet{liftint}. To lift only \typ{POLMOD}s + components, use \tet{liftpol}. Finally, \tet{centerlift} allows to lift + \typ{INTMOD}s and \typ{PADIC}s using centered residues (lift of smallest + absolute value). +Variant: Also available is \fun{GEN}{lift}{GEN x} corresponding to + \kbd{lift0(x,-1)}. + +Function: liftall +Class: basic +Section: conversions +C-Name: liftall +Prototype: G +Help: liftall(x): lifts every element of Z/nZ to Z, of Qp to Q, and of + K[x]/(P) to K[x]. +Description: + (pol):pol liftall($1) + (vec):vec liftall($1) + (gen):gen liftall($1) +Doc: + recursively lift all components of $x$ from $\Z/n\Z$ to $\Z$, + from $\Q_{p}$ to $\Q$ (as \tet{truncate}), and polmods to + polynomials. \typ{FFELT} are not lifted, nor are List elements: you may + convert the latter to vectors first, or use \kbd{apply(liftall,L)}. More + generally, components for which such lifts are meaningless (e.g. character + strings) are copied verbatim. + \bprog + ? liftall(x * (1 + O(3)) + Mod(2,3)) + %1 = x + 2 + ? liftall(x * Mod(y,y^2+1) + Mod(2,3)*Mod(z,z^2)) + %2 = y*x + 2*z + @eprog + +Function: liftint +Class: basic +Section: conversions +C-Name: liftint +Prototype: G +Help: liftint(x): lifts every element of Z/nZ to Z and of Qp to Q. +Description: + (pol):pol liftint($1) + (vec):vec liftint($1) + (gen):gen liftint($1) +Doc: recursively lift all components of $x$ from $\Z/n\Z$ to $\Z$ and + from $\Q_{p}$ to $\Q$ (as \tet{truncate}). + \typ{FFELT} are not lifted, nor are List elements: you may + convert the latter to vectors first, or use \kbd{apply(liftint,L)}. More + generally, components for which such lifts are meaningless (e.g. character + strings) are copied verbatim. + \bprog + ? liftint(x * (1 + O(3)) + Mod(2,3)) + %1 = x + 2 + ? liftint(x * Mod(y,y^2+1) + Mod(2,3)*Mod(z,z^2)) + %2 = Mod(y, y^2 + 1)*x + Mod(Mod(2*z, z^2), y^2 + 1) + @eprog + +Function: liftpol +Class: basic +Section: conversions +C-Name: liftpol +Prototype: G +Help: liftpol(x): lifts every polmod component of x to polynomials. +Description: + (pol):pol liftpol($1) + (vec):vec liftpol($1) + (gen):gen liftpol($1) +Doc: recursively lift all components of $x$ which are polmods to + polynomials. \typ{FFELT} are not lifted, nor are List elements: you may + convert the latter to vectors first, or use \kbd{apply(liftpol,L)}. More + generally, components for which such lifts are meaningless (e.g. character + strings) are copied verbatim. + \bprog + ? liftpol(x * (1 + O(3)) + Mod(2,3)) + %1 = (1 + O(3))*x + Mod(2, 3) + ? liftpol(x * Mod(y,y^2+1) + Mod(2,3)*Mod(z,z^2)) + %2 = y*x + Mod(2, 3)*z + @eprog + +Function: limitnum +Class: basic +Section: sums +C-Name: limitnum0 +Prototype: GDGp +Help: limitnum(expr,{alpha=1}): numerical limit of sequence expr + using Lagrange-Zagier extrapolation; assume u(n) ~ sum a_i n^(-alpha*i). +Doc: Lagrange-Zagier numerical extrapolation of \var{expr}, corresponding to + a sequence $u_{n}$, either given by a closure \kbd{n->u(n)}. I.e., assuming + that $u_{n}$ tends to a finite limit $\ell$, try to determine $\ell$. + + The routine assume that $u_{n}$ has an asymptotic expansion in $n^{-\alpha}$ : + $$u_{n} = \ell + \sum_{i\geq 1} a_{i} n^{-i\alpha}$$ + for some $a_{i}$. It is purely numerical and heuristic, thus may or may not + work on your examples. The expression will be evaluated for $n = 1, 2, + \dots, N$ for an $N = O(B)$ at a bit accuracy bounded by $1.612 B$. + + \bprog + ? limitnum(n -> n*sin(1/n)) + %1 = 1.0000000000000000000000000000000000000 + + ? limitnum(n -> (1+1/n)^n) - exp(1) + %2 = 0.E-37 + + ? limitnum(n -> 2^(4*n+1)*(n!)^4 / (2*n)! /(2*n+1)! ) - Pi + %3 = 0.E -37 + @eprog\noindent + It is not mandatory to specify $\alpha$ when the $u_{n}$ have an asymptotic + expansion in $n^{-1}$. However, if the series in $n^{-1}$ is lacunary, + specifying $\alpha$ allows faster computation: + \bprog + ? \p1000 + ? limitnum(n->(1+1/n^2)^(n^2)) - exp(1) + time = 1min, 44,681 ms. + %4 = 0.E-1001 + ? limitnum(n->(1+1/n^2)^(n^2), 2) - exp(1) + time = 27,271 ms. + %5 = 0.E-1001 \\ still perfect, 4 times faster + @eprog\noindent + When $u_{n}$ has an asymptotic expansion in $n^{-\alpha}$ with $\alpha$ not an + integer, leaving $\alpha$ unspecified will bring an inexact limit. Giving a + satisfying optional argument improves precision; the program runs faster when + the optional argument gives non lacunary series. + \bprog + ? \p50 + ? limitnum(n->(1+1/n^(7/2))^(n^(7/2))) - exp(1) + time = 982 ms. + %6 = 4.13[...] E-12 + ? limitnum(n->(1+1/n^(7/2))^(n^(7/2)), 1/2) - exp(1) + time = 16,745 ms. + %7 = 0.E-57 + ? limitnum(n->(1+1/n^(7/2))^(n^(7/2)), 7/2) - exp(1) + time = 105 ms. + %8 = 0.E-57 + @eprog\noindent + Alternatively, $u_{n}$ may be given by a closure + $N\mapsto [u_{1},\dots, u_{N}]$ + which can often be programmed in a more efficient way, for instance + when $u_{n+1}$ is a simple function of the preceding terms: + \bprog + ? \p2000 + ? limitnum(n -> 2^(4*n+1)*(n!)^4 / (2*n)! /(2*n+1)! ) - Pi + time = 1,755 ms. + %9 = 0.E-2003 + ? vu(N) = \\ exploit hypergeometric property + { my(v = vector(N)); v[1] = 8./3;\ + for (n=2, N, my(q = 4*n^2); v[n] = v[n-1]*q/(q-1));\ + return(v); + } + ? limitnum(vu) - Pi \\ much faster + time = 106 ms. + %11 = 0.E-2003 + @eprog\noindent All sums and recursions can be handled in the same way. + In the above it is essential that $u_{n}$ be defined as a closure because + it must be evaluated at a higher precision than the one expected for the + limit. Make sure that the closure does not depend on a global variable which + would be computed at a priori fixed accuracy. For instance, precomputing + \kbd{v1 = 8.0/3} first and using \kbd{v1} in \kbd{vu} above would be wrong + because the resulting vector of values will use the accuracy of \kbd{v1} + instead of the ambient accuracy at which \kbd{limitnum} will call it. + + Alternatively, and more clumsily, $u_{n}$ may be given by a vector of values: + it must be long and precise enough for the extrapolation + to make sense. Let $B$ be the current \kbd{realbitprecision}, the vector + length must be at least $1.102 B$ and the values computed with bit accuracy + $1.612 B$. + \bprog + ? limitnum(vector(10,n,(1+1/n)^n)) + *** ^-------------------- + *** limitnum: nonexistent component in limitnum: index < 43 + \\ at this accuracy, we must have at least 43 values + ? limitnum(vector(43,n,(1+1/n)^n)) - exp(1) + %12 = 0.E-37 + + ? v = vector(43); + ? s = 0; for(i=1,#v, s += 1/i; v[i]= s - log(i)); + ? limitnum(v) - Euler + %15 = -1.57[...] E-16 + + ? v = vector(43); + \\ ~ 128 bit * 1.612 + ? localbitprec(207);\ + s = 0; for(i=1,#v, s += 1/i; v[i]= s - log(i)); + ? limitnum(v) - Euler + %18 = 0.E-38 + @eprog + + Because of the above problems, the preferred format is thus a closure, + given either a single value or the vector of values $[u_{1},\dots,u_{N}]$. The + function distinguishes between the two formats by evaluating the closure + at $N\neq 1$ and $1$ and checking whether it yields vectors of respective + length $N$ and $1$ or not. + + \misctitle{Warning} The expression is evaluated for $n = 1, 2, \dots, N$ + for an $N = O(B)$ if the current bit accuracy is $B$. If it is not defined + for one of these values, translate or rescale accordingly: + \bprog + ? limitnum(n->log(1-1/n)) \\ can't evaluate at n = 1 ! + *** at top-level: limitnum(n->log(1-1/n)) + *** ^----------------------- + *** in function limitnum: log(1-1/n) + *** ^---------- + *** log: domain error in log: argument = 0 + ? limitnum(n->-log(1-1/(2*n))) + %19 = -6.11[...] E-58 + @eprog + + We conclude with a complicated example. Since the function is heuristic, + it is advisable to check whether it produces the same limit for + $u_{n}, u_{2n}, \dots u_{km}$ for a suitable small multiplier $k$. + The following function implements the recursion for the Motzkin numbers + $M_{n}$ which count the number of ways to draw non intersecting chords between + $n$ points on a circle: + $$ M_{n} = M_{n-1} + \sum_{i < n-1} M_{i} M_{n-2-i} + = ((n+1)M_{n-1}+(3n-3)M_{n-2}) / (n+2).$$ + It is known that $M_{n}^2 \sim \dfrac{9^{n+1}}{12\pi n^{3}}$. + \bprog + \\ [M_k, M_{k*2}, ..., M_{k*N}] / (3^n / n^(3/2)) + vM(N, k = 1) = + { my(q = k*N, V); + if (q == 1, return ([1/3])); + V = vector(q); V[1] = V[2] = 1; + for(n = 2, q - 1, + V[n+1] = ((2*n + 1)*V[n] + 3*(n - 1)*V[n-1]) / (n + 2)); + f = (n -> 3^n / n^(3/2)); + return (vector(N, n, V[n*k] / f(n*k))); + } + ? limitnum(vM) - 3/sqrt(12*Pi) \\ complete junk + %1 = 35540390.753542730306762369615276452646 + ? limitnum(N->vM(N,5)) - 3/sqrt(12*Pi) \\ M_{5n}: better + %2 = 4.130710262178469860 E-25 + ? limitnum(N->vM(N,10)) - 3/sqrt(12*Pi) \\ M_{10n}: perfect + %3 = 0.E-38 + ? \p2000 + ? limitnum(N->vM(N,10)) - 3/sqrt(12*Pi) \\ also at high accuracy + time = 409 ms. + %4 = 1.1048895470044788191 E-2004 + @eprog\noindent In difficult cases such as the above a multiplier of 5 to 10 + is usually sufficient. The above example is typical: a good multiplier usually + remains sufficient when the requested precision increases! + + \synt{limitnum}{void *E, GEN (*u)(void *,GEN,long), GEN alpha, long prec}, where \kbd{u(E, n, prec)} must return $u(n)$ in precision \kbd{prec}. + Also available is + \fun{GEN}{limitnum0}{GEN u, GEN alpha, long prec}, where $u$ + must be a vector of sufficient length as above. + +Function: lindep +Class: basic +Section: linear_algebra +C-Name: lindep0 +Prototype: GD0,L, +Help: lindep(v,{flag=0}): integral linear dependencies between components of v. + flag is optional, and can be 0: default, guess a suitable + accuracy, or positive: accuracy to use for the computation, in decimal + digits. +Doc: \sidx{linear dependence} finds a small nontrivial integral linear + combination between components of $v$. If none can be found return an empty + vector. + + If $v$ is a vector with real/complex entries we use a floating point + (variable precision) LLL algorithm. If $\fl = 0$ the accuracy is chosen + internally using a crude heuristic. If $\fl > 0$ the computation is done with + an accuracy of $\fl$ decimal digits. To get meaningful results in the latter + case, the parameter $\fl$ should be smaller than the number of correct + decimal digits in the input. + + \bprog + ? lindep([sqrt(2), sqrt(3), sqrt(2)+sqrt(3)]) + %1 = [-1, -1, 1]~ + @eprog + + If $v$ is $p$-adic, $\fl$ is ignored and the algorithm LLL-reduces a + suitable (dual) lattice. + \bprog + ? lindep([1, 2 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)]) + %2 = [1, -2]~ + @eprog + + If $v$ is a matrix (or a vector of column vectors, or a vector of row + vectors), $\fl$ is ignored and the function returns a non trivial kernel + vector if one exists, else an empty vector. + \bprog + ? lindep([1,2,3;4,5,6;7,8,9]) + %3 = [1, -2, 1]~ + ? lindep([[1,0], [2,0]]) + %4 = [2, -1]~ + ? lindep([[1,0], [0,1]]) + %5 = []~ + @eprog + + If $v$ contains polynomials or power series over some base field, finds a + linear relation with coefficients in the field. + \bprog + ? lindep([x*y, x^2 + y, x^2*y + x*y^2, 1]) + %4 = [y, y, -1, -y^2]~ + @eprog\noindent For better control, it is preferable to use \typ{POL} rather + than \typ{SER} in the input, otherwise one gets a linear combination which is + $t$-adically small, but not necessarily $0$. Indeed, power series are first + converted to the minimal absolute accuracy occurring among the entries of $v$ + (which can cause some coefficients to be ignored), then truncated to + polynomials: + \bprog + ? v = [t^2+O(t^4), 1+O(t^2)]; L=lindep(v) + %1 = [1, 0]~ + ? v*L + %2 = t^2+O(t^4) \\ small but not 0 + @eprog + +Function: listcreate +Class: basic +Section: programming/specific +C-Name: listcreate_gp +Prototype: D0,L, +Obsolete: 2007-08-10 +Help: listcreate({n}): this function is obsolete, use List(). +Description: + (?gen):list mklist() +Doc: This function is obsolete, use \kbd{List}. + + Creates an empty list. This routine used to have a mandatory argument, + which is now ignored (for backward compatibility). + % \syn{NO} + +Function: listinsert +Class: basic +Section: programming/specific +C-Name: listinsert0 +Prototype: mWGL +Help: listinsert(~L,x,n): insert x at index n in list L, shifting the + remaining elements to the right. +Description: + (list, gen, small):gen listinsert($1, $2, $3) +Doc: inserts the object $x$ at + position $n$ in $L$ (which must be of type \typ{LIST}). + This has complexity $O(\#L - n + 1)$: all the + remaining elements of \var{list} (from position $n+1$ onwards) are shifted + to the right. If $n$ is greater than the list length, appends $x$. + \bprog + ? L = List([1,2,3]); + ? listput(~L, 4); L \\ listput inserts at end + %4 = List([1, 2, 3, 4]) + ? listinsert(~L, 5, 1); L \\insert at position 1 + %5 = List([5, 1, 2, 3, 4]) + ? listinsert(~L, 6, 1000); L \\ trying to insert beyond position #L + %6 = List([5, 1, 2, 3, 4, 6]) \\ ... inserts at the end + @eprog\noindent Note the \kbd{\til L}: this means that the function is + called with a \emph{reference} to \kbd{L} and changes \kbd{L} in place. + +Function: listkill +Class: basic +Section: programming/specific +C-Name: listkill +Prototype: vW +Obsolete: 2007-08-10 +Help: listkill(~L): obsolete, retained for backward compatibility. +Doc: obsolete, retained for backward compatibility. Just use \kbd{L = List()} + instead of \kbd{listkill(L)}. In most cases, you won't even need that, e.g. + local variables are automatically cleared when a user function returns. + +Function: listpop +Class: basic +Section: programming/specific +C-Name: listpop0 +Prototype: vWD0,L, +Help: listpop(~list,{n}): removes n-th element from list. If n is + omitted or greater than the current list length, removes last element. +Description: + (list, small):void listpop($1, $2) +Doc: + removes the $n$-th element of the list + \var{list} (which must be of type \typ{LIST}). If $n$ is omitted, + or greater than the list current length, removes the last element. + If the list is already empty, do nothing. This runs in time $O(\#L - n + 1)$. + \bprog + ? L = List([1,2,3,4]); + ? listpop(~L); L \\ remove last entry + %2 = List([1, 2, 3]) + ? listpop(~L, 1); L \\ remove first entry + %3 = List([2, 3]) + @eprog\noindent Note the \kbd{\til L}: this means that the function is + called with a \emph{reference} to \kbd{L} and changes \kbd{L} in place. + +Function: listput +Class: basic +Section: programming/specific +C-Name: listput0 +Prototype: mWGD0,L, +Help: listput(~list,x,{n}): sets n-th element of list equal to x. If n is + omitted or greater than the current list length, appends x. +Description: + (list, gen, small):gen listput($1, $2, $3) +Doc: + sets the $n$-th element of the list + \var{list} (which must be of type \typ{LIST}) equal to $x$. If $n$ is omitted, + or greater than the list length, appends $x$. + \bprog + ? L = List(); + ? listput(~L, 1) + ? listput(~L, 2) + ? L + %4 = List([1, 2]) + @eprog\noindent Note the \kbd{\til L}: this means that the function is + called with a \emph{reference} to \kbd{L} and changes \kbd{L} in place. + + You may put an element into an occupied cell (not changing the + list length), but it is easier to use the standard \kbd{list[n] = x} + construct. + \bprog + ? listput(~L, 3, 1) \\ insert at position 1 + ? L + %6 = List([3, 2]) + ? L[2] = 4 \\ simpler + %7 = List([3, 4]) + ? L[10] = 1 \\ can't insert beyond the end of the list + *** at top-level: L[10]=1 + *** ^------ + *** nonexistent component: index > 2 + ? listput(L, 1, 10) \\ but listput can + ? L + %9 = List([3, 2, 1]) + @eprog + + This function runs in time $O(\#L)$ in the worst case (when the list must + be reallocated), but in time $O(1)$ on average: any number of successive + \kbd{listput}s run in time $O(\#L)$, where $\#L$ denotes the list + \emph{final} length. + +Function: listsort +Class: basic +Section: programming/specific +C-Name: listsort +Prototype: vWD0,L, +Help: listsort(~L,{flag=0}): sort the list L in place. If flag is nonzero, + suppress all but one occurrence of each element in list. +Doc: sorts the \typ{LIST} \var{list} in place, with respect to the (somewhat + arbitrary) universal comparison function \tet{cmp}. In particular, the + ordering is the same as for sets and \tet{setsearch} can be used on a sorted + list. No value is returned. If $\fl$ is nonzero, suppresses all repeated + coefficients. + \bprog + ? L = List([1,2,4,1,3,-1]); listsort(~L); L + %1 = List([-1, 1, 1, 2, 3, 4]) + ? setsearch(L, 4) + %2 = 6 + ? setsearch(L, -2) + %3 = 0 + ? listsort(~L, 1); L \\ remove duplicates + %4 = List([-1, 1, 2, 3, 4]) + @eprog\noindent Note the \kbd{\til L}: this means that the function is + called with a \emph{reference} to \kbd{L} and changes \kbd{L} in place: + this is faster than the \kbd{vecsort} command since the list + is sorted in place and we avoid unnecessary copies. + \bprog + ? v = vector(100,i,random); L = List(v); + ? for(i=1,10^4, vecsort(v)) + time = 162 ms. + ? for(i=1,10^4, vecsort(L)) + time = 162 ms. + ? for(i=1,10^4, listsort(~L)) + time = 63 ms. + @eprog + +Function: lngamma +Class: basic +Section: transcendental +C-Name: glngamma +Prototype: Gp +Help: lngamma(x): logarithm of the gamma function of x. +Doc: principal branch of the logarithm of the gamma function of $x$. This + function is analytic on the complex plane with nonpositive integers + removed, and can have much larger arguments than \kbd{gamma} itself. + + For $x$ a power series such that $x(0)$ is not a pole of \kbd{gamma}, + compute the Taylor expansion. (PARI only knows about regular power series + and can't include logarithmic terms.) + \bprog + ? lngamma(1+x+O(x^2)) + %1 = -0.57721566490153286060651209008240243104*x + O(x^2) + ? lngamma(x+O(x^2)) + *** at top-level: lngamma(x+O(x^2)) + *** ^----------------- + *** lngamma: domain error in lngamma: valuation != 0 + ? lngamma(-1+x+O(x^2)) + *** lngamma: Warning: normalizing a series with 0 leading term. + *** at top-level: lngamma(-1+x+O(x^2)) + *** ^-------------------- + *** lngamma: domain error in intformal: residue(series, pole) != 0 + @eprog + For $x$ a \typ{PADIC}, return the $p$-adic $\log\Gamma_{p}$ function, which + is the $p$-adic logarithm of Morita's gamma function for $x \in \Z_{p}$, + and Diamond's function if $|x| > 1$. + \bprog + ? lngamma(5+O(5^7)) + %2 = 4*5^2 + 4*5^3 + 5^4 + 2*5^5 + O(5^6) + ? log(gamma(5+O(5^7))) + %3 = 4*5^2 + 4*5^3 + 5^4 + 2*5^5 + O(5^6) + ? lngamma(1/5+O(5^4)) + %4 = 4*5^-1 + 4 + 2*5 + 5^2 + 5^3 + O(5^4) + ? gamma(1/5+O(5^4)) + *** at top-level: gamma(1/5+O(5^4)) + *** ^----------------- + *** gamma: domain error in gamma: v_p(x) < 0 + @eprog + +Function: local +Class: basic +Section: programming/specific +Help: local(x,...,z): declare x,...,z as (dynamically scoped) local variables. + +Function: localbitprec +Class: basic +Section: programming/specific +C-Name: localbitprec +Prototype: vG +Help: localbitprec(p): set the real precision to p bits in the dynamic scope. +Doc: set the real precision to $p$ bits in the dynamic scope. + All computations are performed as if \tet{realbitprecision} was $p$: + transcendental constants (e.g.~\kbd{Pi}) and + conversions from exact to floating point inexact data use $p$ bits, as well as + iterative routines implicitly using a floating point + accuracy as a termination criterion (e.g.~\tet{solve} or \tet{intnum}). + But \kbd{realbitprecision} itself is unaffected + and is ``unmasked'' when we exit the dynamic (\emph{not} lexical) scope. + In effect, this is similar to + \bprog + my(bit = default(realbitprecision)); + default(realbitprecision,p); + ... + default(realbitprecision, bit); + @eprog\noindent but is both less cumbersome, cleaner (no need to manipulate + a global variable, which in fact never changes and is only temporarily masked) + and more robust: if the above computation is interrupted or an exception + occurs, \kbd{realbitprecision} will not be restored as intended. + + Such \kbd{localbitprec} statements can be nested, the innermost one taking + precedence as expected. Beware that \kbd{localbitprec} follows the semantic of + \tet{local}, not \tet{my}: a subroutine called from \kbd{localbitprec} scope + uses the local accuracy: + \bprog + ? f()=bitprecision(1.0); + ? f() + %2 = 128 + ? localbitprec(1000); f() + %3 = 1024 + @eprog\noindent Note that the bit precision of \emph{data} (\kbd{1.0} in the + above example) increases by steps of 64 (32 on a 32-bit machine) so we get + $1024$ instead of the expected $1000$; \kbd{localbitprec} bounds the + relative error exactly as specified in functions that support that + granularity (e.g.~\kbd{lfun}), and rounded to the next multiple of 64 + (resp.~32) everywhere else. + + \misctitle{Warning} Changing \kbd{realbitprecision} or \kbd{realprecision} + in programs is deprecated in favor of \kbd{localbitprec} and + \kbd{localprec}. Think about the \kbd{realprecision} and + \kbd{realbitprecision} defaults as interactive commands for the \kbd{gp} + interpreter, best left out of GP programs. Indeed, the above rules imply that + mixing both constructs yields surprising results: + + \bprog + ? \p38 + ? localprec(19); default(realprecision,1000); Pi + %1 = 3.141592653589793239 + ? \p + realprecision = 1001 significant digits (1000 digits displayed) + @eprog\noindent Indeed, \kbd{realprecision} itself is ignored within + \kbd{localprec} scope, so \kbd{Pi} is computed to a low accuracy. And when + we leave the \kbd{localprec} scope, \kbd{realprecision} only regains precedence, + it is not ``restored'' to the original value. + %\syn{NO} + +Function: localprec +Class: basic +Section: programming/specific +C-Name: localprec +Prototype: vG +Help: localprec(p): set the real precision to p in the dynamic scope + and return p. +Doc: set the real precision to $p$ in the dynamic scope and return $p$. + All computations are performed as if \tet{realprecision} was $p$: + transcendental constants (e.g.~\kbd{Pi}) and + conversions from exact to floating point inexact data use $p$ decimal + digits, as well as iterative routines implicitly using a floating point + accuracy as a termination criterion (e.g.~\tet{solve} or \tet{intnum}). + But \kbd{realprecision} itself is unaffected + and is ``unmasked'' when we exit the dynamic (\emph{not} lexical) scope. + In effect, this is similar to + \bprog + my(prec = default(realprecision)); + default(realprecision,p); + ... + default(realprecision, prec); + @eprog\noindent but is both less cumbersome, cleaner (no need to manipulate + a global variable, which in fact never changes and is only temporarily masked) + and more robust: if the above computation is interrupted or an exception + occurs, \kbd{realprecision} will not be restored as intended. + + Such \kbd{localprec} statements can be nested, the innermost one taking + precedence as expected. Beware that \kbd{localprec} follows the semantic of + \tet{local}, not \tet{my}: a subroutine called from \kbd{localprec} scope + uses the local accuracy: + \bprog + ? f()=precision(1.); + ? f() + %2 = 38 + ? localprec(19); f() + %3 = 19 + @eprog\noindent + \misctitle{Warning} Changing \kbd{realprecision} itself in programs is + now deprecated in favor of \kbd{localprec}. Think about the + \kbd{realprecision} default as an interactive command for the \kbd{gp} + interpreter, best left out of GP programs. Indeed, the above rules + imply that mixing both constructs yields surprising results: + \bprog + ? \p38 + ? localprec(19); default(realprecision,100); Pi + %1 = 3.141592653589793239 + ? \p + realprecision = 115 significant digits (100 digits displayed) + @eprog\noindent Indeed, \kbd{realprecision} itself is ignored within + \kbd{localprec} scope, so \kbd{Pi} is computed to a low accuracy. And when + we leave \kbd{localprec} scope, \kbd{realprecision} only regains precedence, + it is not ``restored'' to the original value. + %\syn{NO} + +Function: log +Class: basic +Section: transcendental +C-Name: glog +Prototype: Gp +Help: log(x): natural logarithm of x. +Description: + (gen):gen:prec glog($1, $prec) +Doc: principal branch of the natural logarithm of + $x \in \C^{*}$, i.e.~such that $\Im(\log(x))\in{} ]-\pi,\pi]$. + The branch cut lies + along the negative real axis, continuous with quadrant 2, i.e.~such that + $\lim_{b\to 0^{+}} \log (a+bi) = \log a$ for $a \in\R^{*}$. + The result is complex + (with imaginary part equal to $\pi$) if $x\in \R$ and $x < 0$. In general, + the algorithm uses the formula + $$\log(x) \approx {\pi\over 2\text{agm}(1, 4/s)} - m \log 2, $$ + if $s = x 2^{m}$ is large enough. (The result is exact to $B$ bits provided + $s > 2^{B/2}$.) At low accuracies, the series expansion near $1$ is used. + + $p$-adic arguments are also accepted for $x$, with the convention that + $\log(p)=0$. Hence in particular $\exp(\log(x))/x$ is not in general equal to + 1 but to a $(p-1)$-th root of unity (or $\pm1$ if $p=2$) times a power of $p$. +Variant: For a \typ{PADIC} $x$, the function + \fun{GEN}{Qp_log}{GEN x} is also available. + +Function: log1p +Class: basic +Section: transcendental +C-Name: glog1p +Prototype: Gp +Help: log1p(x): log(1+x) +Doc: return $\log(1+x)$, computed in a way that is also accurate + when the real part of $x$ is near $0$. This is the reciprocal function + of \kbd{expm1}$(x) = \exp(x)-1$. + \bprog + ? default(realprecision, 10000); x = Pi*1e-100; + ? (expm1(log1p(x)) - x) / x + %2 = -7.668242895059371866 E-10019 + ? (log1p(expm1(x)) - x) / x + %3 = -7.668242895059371866 E-10019 + @eprog\noindent When $x$ is small, this function is both faster and more + accurate than $\log(1+x)$: + \bprog + ? \p38 + ? x = 1e-20; + ? localprec(100); c = log1p(x); \\ reference point + ? a = log1p(x); abs((a - c)/c) + %6 = 0.E-38 + ? b = log(1+x); abs((b - c)/c) \\ slightly less accurate + %7 = 1.5930919111324522770 E-38 + ? for (i=1,10^5,log1p(x)) + time = 81 ms. + ? for (i=1,10^5,log(1+x)) + time = 100 ms. \\ slower, too + @eprog + +Function: logint +Class: basic +Section: number_theoretical +C-Name: logint0 +Prototype: lGGD& +Help: logint(x,b,{&z}): return the largest non-negative integer e so that + b^e <= x, where b > 1 is an integer and x >= 1 is a real number. If the + parameter z is present, set it to b^e. +Description: + (int,2):small expi($1) + (gen,gen):small logint0($1, $2, NULL) + (gen,gen,&int):small logint0($1, $2, &$3) +Doc: Return the largest non-negative integer $e$ so that $b^{e} \leq x$, where + $b > 1$ is an integer and $x \geq 1$ is a real number. If the parameter $z$ + is present, set it to $b^{e}$. + \bprog + ? logint(1000, 2) + %1 = 9 + ? 2^9 + %2 = 512 + ? logint(1000, 2, &z) + %3 = 9 + ? z + %4 = 512 + ? logint(Pi^2, 2, &z) + %5 = 3 + ? z + %6 = 8 + @eprog\noindent The number of digits used to write $x$ in base $b$ is + \kbd{1 + logint(x,b)}: + \bprog + ? #digits(1000!, 10) + %5 = 2568 + ? logint(1000!, 10) + %6 = 2567 + @eprog\noindent This function may conveniently replace + \bprog + floor( log(x) / log(b) ) + @eprog\noindent which may not give the correct answer since PARI + does not guarantee exact rounding. + +Function: mapapply +Class: basic +Section: programming/specific +C-Name: mapapply +Prototype: WGGDG +Help: mapapply(~M,x,f,{u}): applies the closure f to the image of x by the + map M and returns the evaluation of f. +Doc: applies the closure $f$ to the image $y$ of $x$ by the map $M$ + and returns the evaluation $f(y)$. The closure $f$ is allowed to + modify the components of $y$ in place. If $M$ is not defined at $x$, and + the optional argument \kbd{u} (for \var{undefined}) is present and is + a closure of arity $0$, return the evaluation $u()$. + + To apply $f$ to \emph{all} entries (values) of $M$, use \kbd{apply}$(f, M)$ + instead. There are two main use-cases: + + \item performing a computation on a value directly, without using + \kbd{mapget}, avoiding a copy: + \bprog + ? M = Map(); mapput(~M, "a", mathilbert(2000)); + ? matsize(mapget(M, "a")) \\ Slow because mapget(M, "a") copies the value + %2 = [2000, 2000] + time = 101 ms. + ? mapapply(~M, "a", matsize) \\ Fast + time = 0 ms. + %3 = [2000, 2000] + @eprog + + \item modifying a value in place, for example to append an element to a value + in a map of lists. This requires to use \kbd{\til} in the function + declaration. In the following \kbd{maplistput}, $M$ is a map of lists and we + append $v$ to the list \kbd{mapget(M,k)}, except this is done in place ! + When the map is undefined at $k$, we use the $u$(ndefined) argument + \kbd{()->List(v)} to convert $v$ to a list then insert it in the map: + \bprog + ? maplistput(~M, k, v) = mapapply(~M, k, (~y)->listput(~y,v), ()->List(v)); + + ? M = Map(); + %2 = Map([;]) + ? maplistput(~M, "a", 1); M + %3 = Map(["a", List([1])]) + ? maplistput(~M, "a", 2); M + %4 = Map(["a", List([1, 2])]) + ? maplistput(~M, "b", 3); M + %5 = Map(["a", List([1, 2]); "b", List([3])]) + ? maplistput(~M, "a", 4); M + %6 = Map(["a", List([1, 2, 4]); "b", List([])]) + @eprog + +Function: mapdelete +Class: basic +Section: programming/specific +C-Name: mapdelete +Prototype: vWG +Help: mapdelete(~M,x): removes x from the domain of the map M. +Doc: removes $x$ from the domain of the map $M$. + \bprog + ? M = Map(["a",1; "b",3; "c",7]); + ? mapdelete(M,"b"); + ? Mat(M) + ["a" 1] + + ["c" 7] + @eprog + +Function: mapget +Class: basic +Section: programming/specific +C-Name: mapget +Prototype: GG +Help: mapget(M,x): returns the image of x by the map M. +Doc: Returns the image of $x$ by the map $M$. + \bprog + ? M=Map(["a",23;"b",43]); + ? mapget(M,"a") + %2 = 23 + ? mapget(M,"b") + %3 = 43 + @eprog\noindent Raises an exception when the key $x$ is not present in $M$. + \bprog + ? mapget(M,"c") + *** at top-level: mapget(M,"c") + *** ^------------- + *** mapget: nonexistent component in mapget: index not in map + @eprog + +Function: mapisdefined +Class: basic +Section: programming/specific +C-Name: mapisdefined +Prototype: iGGD& +Help: mapisdefined(M,x,{&z}): true (1) if x has an image by the map M, + false (0) otherwise. + If z is present, set it to the image of x, if it exists. +Doc: Returns true ($1$) if $x$ has an image by the map $M$, false ($0$) + otherwise. If $z$ is present, set $z$ to the image of $x$, if it exists. + \bprog + ? M1 = Map([1, 10; 2, 20]); + ? mapisdefined(M1,3) + %1 = 0 + ? mapisdefined(M1, 1, &z) + %2 = 1 + ? z + %3 = 10 + @eprog + + \bprog + ? M2 = Map(); N = 19; + ? for (a=0, N-1, mapput(M2, a^3%N, a)); + ? {for (a=0, N-1, + if (mapisdefined(M2, a, &b), + printf("%d is the cube of %d mod %d\n",a,b,N)));} + 0 is the cube of 0 mod 19 + 1 is the cube of 11 mod 19 + 7 is the cube of 9 mod 19 + 8 is the cube of 14 mod 19 + 11 is the cube of 17 mod 19 + 12 is the cube of 15 mod 19 + 18 is the cube of 18 mod 19 + @eprog + +Function: mapput +Class: basic +Section: programming/specific +C-Name: mapput +Prototype: vWGG +Help: mapput(~M,x,y): associates x to y in the map M. +Doc: Associates $x$ to $y$ in the map $M$. The value $y$ can be retrieved + with \tet{mapget}. + \bprog + ? M = Map(); + ? mapput(~M, "foo", 23); + ? mapput(~M, 7718, "bill"); + ? mapget(M, "foo") + %4 = 23 + ? mapget(M, 7718) + %5 = "bill" + ? Vec(M) \\ keys + %6 = [7718, "foo"] + ? Mat(M) + %7 = + [ 7718 "bill"] + + ["foo" 23] + @eprog + +Function: matadjoint +Class: basic +Section: linear_algebra +C-Name: matadjoint0 +Prototype: GD0,L, +Help: matadjoint(M,{flag=0}): adjoint matrix of M using Leverrier-Faddeev's + algorithm. If flag is 1, computes the characteristic polynomial independently + first. +Doc: + \idx{adjoint matrix} of $M$, i.e.~a matrix $N$ + of cofactors of $M$, satisfying $M*N=\det(M)*\Id$. $M$ must be a + (not necessarily invertible) square matrix of dimension $n$. + If $\fl$ is 0 or omitted, we try to use Leverrier-Faddeev's algorithm, + which assumes that $n!$ invertible. If it fails or $\fl = 1$, + computes $T = \kbd{charpoly}(M)$ independently first and returns + $(-1)^{n-1} (T(x)-T(0))/x$ evaluated at $M$. + \bprog + ? a = [1,2,3;3,4,5;6,7,8] * Mod(1,4); + ? matadjoint(a) + %2 = + [Mod(1, 4) Mod(1, 4) Mod(2, 4)] + + [Mod(2, 4) Mod(2, 4) Mod(0, 4)] + + [Mod(1, 4) Mod(1, 4) Mod(2, 4)] + @eprog\noindent + Both algorithms use $O(n^{4})$ operations in the base ring. Over a field, + they are usually slower than computing the characteristic polynomial or + the inverse of $M$ directly. +Variant: Also available are + \fun{GEN}{adj}{GEN x} ($\fl=0$) and + \fun{GEN}{adjsafe}{GEN x} ($\fl=1$). + +Function: matalgtobasis +Class: basic +Section: number_fields +C-Name: matalgtobasis +Prototype: GG +Obsolete: 2016-08-08 +Help: matalgtobasis(nf,x): nfalgtobasis applied to every element of the + vector or matrix x. +Doc: This function is deprecated, use \kbd{apply}. + + $\var{nf}$ being a number field in \kbd{nfinit} format, and $x$ a + (row or column) vector or matrix, apply \tet{nfalgtobasis} to each entry + of $x$. + +Function: matbasistoalg +Class: basic +Section: number_fields +C-Name: matbasistoalg +Prototype: GG +Obsolete: 2016-08-08 +Help: matbasistoalg(nf,x): nfbasistoalg applied to every element of the + matrix or vector x. +Doc: This function is deprecated, use \kbd{apply}. + + $\var{nf}$ being a number field in \kbd{nfinit} format, and $x$ a + (row or column) vector or matrix, apply \tet{nfbasistoalg} to each entry + of $x$. + +Function: matcompanion +Class: basic +Section: linear_algebra +C-Name: matcompanion +Prototype: G +Help: matcompanion(x): companion matrix to polynomial x. +Doc: + the left companion matrix to the nonzero polynomial $x$. + +Function: matconcat +Class: basic +Section: linear_algebra +C-Name: matconcat +Prototype: G +Help: matconcat(v): concatenate the entries of v and return the resulting + matrix. +Doc: returns a \typ{MAT} built from the entries of $v$, which may + be a \typ{VEC} (concatenate horizontally), a \typ{COL} (concatenate + vertically), or a \typ{MAT} (concatenate vertically each column, and + concatenate vertically the resulting matrices). The entries of $v$ are always + considered as matrices: they can themselves be \typ{VEC} (seen as a row + matrix), a \typ{COL} seen as a column matrix), a \typ{MAT}, or a scalar (seen + as an $1 \times 1$ matrix). + \bprog + ? A=[1,2;3,4]; B=[5,6]~; C=[7,8]; D=9; + ? matconcat([A, B]) \\ horizontal + %1 = + [1 2 5] + + [3 4 6] + ? matconcat([A, C]~) \\ vertical + %2 = + [1 2] + + [3 4] + + [7 8] + ? matconcat([A, B; C, D]) \\ block matrix + %3 = + [1 2 5] + + [3 4 6] + + [7 8 9] + @eprog\noindent + If the dimensions of the entries to concatenate do not match up, the above + rules are extended as follows: + + \item each entry $v_{i,j}$ of $v$ has a natural length and height: $1 \times + 1$ for a scalar, $1 \times n$ for a \typ{VEC} of length $n$, $n \times 1$ + for a \typ{COL}, $m \times n$ for an $m\times n$ \typ{MAT} + + \item let $H_{i}$ be the maximum over $j$ of the lengths of the $v_{i,j}$, + let $L_{j}$ be the maximum over $i$ of the heights of the $v_{i,j}$. + The dimensions of the $(i,j)$-th block in the concatenated matrix are + $H_{i} \times L_{j}$. + + \item a scalar $s = v_{i,j}$ is considered as $s$ times an identity matrix + of the block dimension $\min (H_{i},L_{j})$ + + \item blocks are extended by 0 columns on the right and 0 rows at the + bottom, as needed. + + \bprog + ? matconcat([1, [2,3]~, [4,5,6]~]) \\ horizontal + %4 = + [1 2 4] + + [0 3 5] + + [0 0 6] + ? matconcat([1, [2,3], [4,5,6]]~) \\ vertical + %5 = + [1 0 0] + + [2 3 0] + + [4 5 6] + ? matconcat([B, C; A, D]) \\ block matrix + %6 = + [5 0 7 8] + + [6 0 0 0] + + [1 2 9 0] + + [3 4 0 9] + ? U=[1,2;3,4]; V=[1,2,3;4,5,6;7,8,9]; + ? matconcat(matdiagonal([U, V])) \\ block diagonal + %7 = + [1 2 0 0 0] + + [3 4 0 0 0] + + [0 0 1 2 3] + + [0 0 4 5 6] + + [0 0 7 8 9] + @eprog + +Function: matdet +Class: basic +Section: linear_algebra +C-Name: det0 +Prototype: GD0,L, +Help: matdet(x,{flag=0}): determinant of the matrix x using an appropriate + algorithm depending on the coefficients. If (optional) flag is set to 1, use + classical Gaussian elimination (usually worse than the default). +Description: + (gen, ?0):gen det($1) + (gen, 1):gen det2($1) + (gen, #small):gen $"incorrect flag in matdet" + (gen, small):gen det0($1, $2) +Doc: determinant of the square matrix $x$. + + If $\fl=0$, uses an appropriate algorithm depending on the coefficients: + + \item integer entries: modular method due to Dixon, Pernet and Stein. + + \item real or $p$-adic entries: classical Gaussian elimination using maximal + pivot. + + \item intmod entries: classical Gaussian elimination using first nonzero + pivot. + + \item other cases: Gauss-Bareiss. + + If $\fl=1$, uses classical Gaussian elimination with appropriate pivoting + strategy (maximal pivot for real or $p$-adic coefficients). This is usually + worse than the default. +Variant: Also available are \fun{GEN}{det}{GEN x} ($\fl=0$), + \fun{GEN}{det2}{GEN x} ($\fl=1$) and \fun{GEN}{ZM_det}{GEN x} for integer + entries. + +Function: matdetint +Class: basic +Section: linear_algebra +C-Name: detint +Prototype: G +Help: matdetint(B): some multiple of the determinant of the lattice + generated by the columns of B (0 if not of maximal rank). Useful with + mathnfmod. +Doc: + Let $B$ be an $m\times n$ matrix with integer coefficients. The + \emph{determinant} $D$ of the lattice generated by the columns of $B$ is + the square root of $\det(B^{T} B)$ if $B$ has maximal rank $m$, and $0$ + otherwise. + + This function uses the Gauss-Bareiss algorithm to compute a positive + \emph{multiple} of $D$. When $B$ is square, the function actually returns + $D = |\det B|$. + + This function is useful in conjunction with \kbd{mathnfmod}, which needs to + know such a multiple. If the rank is maximal but the matrix is nonsquare, + you can obtain $D$ exactly using + \bprog + matdet( mathnfmod(B, matdetint(B)) ) + @eprog\noindent + Note that as soon as one of the dimensions gets large ($m$ or $n$ is larger + than 20, say), it will often be much faster to use \kbd{mathnf(B, 1)} or + \kbd{mathnf(B, 4)} directly. + +Function: matdetmod +Class: basic +Section: linear_algebra +C-Name: matdetmod +Prototype: GG +Help: matdetmod(x,d): determinant of the matrix x modulo d. +Doc: Given a matrix $x$ with \typ{INT} entries and $d$ an arbitrary positive + integer, return the determinant of $x$ modulo $d$. + + \bprog + ? A = [4,2,3; 4,5,6; 7,8,9] + + ? matdetmod(A,27) + %2 = 9 + @eprog Note that using the generic function \kbd{matdet} on a matrix with + \typ{INTMOD} entries uses Gaussian reduction and will fail in general when + the modulus is not prime. + \bprog + ? matdet(A * Mod(1,27)) + *** at top-level: matdet(A*Mod(1,27)) + *** ^------------------ + *** matdet: impossible inverse in Fl_inv: Mod(3, 27). + @eprog + +Function: matdiagonal +Class: basic +Section: linear_algebra +C-Name: diagonal +Prototype: G +Help: matdiagonal(x): creates the diagonal matrix whose diagonal entries are + the entries of the vector x. +Doc: $x$ being a vector, creates the diagonal matrix + whose diagonal entries are those of $x$. + \bprog + ? matdiagonal([1,2,3]); + %1 = + [1 0 0] + + [0 2 0] + + [0 0 3] + @eprog\noindent Block diagonal matrices are easily created using + \tet{matconcat}: + \bprog + ? U=[1,2;3,4]; V=[1,2,3;4,5,6;7,8,9]; + ? matconcat(matdiagonal([U, V])) + %1 = + [1 2 0 0 0] + + [3 4 0 0 0] + + [0 0 1 2 3] + + [0 0 4 5 6] + + [0 0 7 8 9] + @eprog + +Function: mateigen +Class: basic +Section: linear_algebra +C-Name: mateigen +Prototype: GD0,L,p +Help: mateigen(x,{flag=0}): complex eigenvectors of the matrix x given as + columns of a matrix H. If flag=1, return [L,H], where L contains the + eigenvalues and H the corresponding eigenvectors. +Doc: returns the (complex) eigenvectors of $x$ as columns of a matrix. + If $\fl=1$, return $[L,H]$, where $L$ contains the + eigenvalues and $H$ the corresponding eigenvectors; multiple eigenvalues are + repeated according to the eigenspace dimension (which may be less + than the eigenvalue multiplicity in the characteristic polynomial). + + This function first computes the characteristic polynomial of $x$ and + approximates its complex roots $(\lambda_{i})$, then tries to compute the + eigenspaces as kernels of the $x - \lambda_{i}$. This algorithm is + ill-conditioned and is likely to miss kernel vectors if some roots of the + characteristic polynomial are close, in particular if it has multiple roots. + \bprog + ? A = [13,2; 10,14]; mateigen(A) + %1 = + [-1/2 2/5] + + [ 1 1] + ? [L,H] = mateigen(A, 1); + ? L + %3 = [9, 18] + ? H + %4 = + [-1/2 2/5] + + [ 1 1] + ? A * H == H * matdiagonal(L) + %5 = 1 + @eprog\noindent + For symmetric matrices, use \tet{qfjacobi} instead; for Hermitian matrices, + compute + \bprog + A = real(x); + B = imag(x); + y = matconcat([A, -B; B, A]); + @eprog\noindent and apply \kbd{qfjacobi} to $y$. +Variant: Also available is \fun{GEN}{eigen}{GEN x, long prec} ($\fl = 0$) + +Function: matfrobenius +Class: basic +Section: linear_algebra +C-Name: matfrobenius +Prototype: GD0,L,Dn +Help: matfrobenius(M,{flag},{v='x}): return the Frobenius form of the square + matrix M. If flag is 1, return only the elementary divisors as a vector of + polynomials in the variable v. If flag is 2, return a two-components vector + [F,B] where F is the Frobenius form and B is the basis change so that + M=B^-1*F*B. +Doc: returns the Frobenius form of + the square matrix \kbd{M}. If $\fl=1$, returns only the elementary divisors as + a vector of polynomials in the variable \kbd{v}. If $\fl=2$, returns a + two-components vector [F,B] where \kbd{F} is the Frobenius form and \kbd{B} is + the basis change so that $M=B^{-1}FB$. + +Function: mathess +Class: basic +Section: linear_algebra +C-Name: hess +Prototype: G +Help: mathess(x): Hessenberg form of x. +Doc: returns a matrix similar to the square matrix $x$, which is in upper Hessenberg + form (zero entries below the first subdiagonal). + +Function: mathilbert +Class: basic +Section: linear_algebra +C-Name: mathilbert +Prototype: L +Help: mathilbert(n): Hilbert matrix of order n. +Doc: creates the \idx{Hilbert matrix} of order $n \geq 0$, i.e.~the square + matrix $H$ whose coefficient $H[i,j]$ is $1 / (i+j-1)$. This matrix is + ill-conditionned but its inverse has integer entries. + +Function: mathnf +Class: basic +Section: linear_algebra +C-Name: mathnf0 +Prototype: GD0,L, +Help: mathnf(M,{flag=0}): (upper triangular) Hermite normal form of M, basis + for the lattice formed by the columns of M. Basic values of flag are + 0 (default): only return the Hermite normal form H, + 1: return [H,U] such that H is the HNF of M, and U is an invertible matrix + such that MU=H. These two use a naive algorithm; larger values of flag + correspond to more involved algorithms and are restricted to integer + matrices; flag = 4: returns [H,U] using LLL reduction along the way; + flag = 5: return [H,U,P] where P is a permutation of row indices such that + P applied to M U is H. +Doc: let $R$ be a Euclidean ring, equal to $\Z$ or to $K[X]$ for some field + $K$. If $M$ is a (not necessarily square) matrix with entries in $R$, this + routine finds the \emph{upper triangular} \idx{Hermite normal form} of $M$. + If the rank of $M$ is equal to its number of rows, this is a square + matrix. In general, the columns of the result form a basis of the $R$-module + spanned by the columns of $M$. + + The values of $\fl$ are: + + \item 0 (default): only return the Hermite normal form $H$ + + \item 1 (complete output): return $[H,U]$, where $H$ is the Hermite + normal form of $M$, and $U$ is a transformation matrix such that $MU=[0|H]$. + The matrix $U$ belongs to $\text{GL}(R)$. When $M$ has a large kernel, the + entries of $U$ are in general huge. + + \noindent For these two values, we use a naive algorithm, which behaves well + in small dimension only. Larger values correspond to different algorithms, + are restricted to \emph{integer} matrices, and all output the unimodular + matrix $U$. From now on all matrices have integral entries. + + \item $\fl=4$, returns $[H,U]$ as in ``complete output'' above, using a + variant of \idx{LLL} reduction along the way. The matrix $U$ is provably + small in the $L_{2}$ sense, and often close to optimal; but the + reduction is in general slow, although provably polynomial-time. + + If $\fl=5$, uses Batut's algorithm and output $[H,U,P]$, such that $H$ and + $U$ are as before and $P$ is a permutation of the rows such that $P$ applied + to $MU$ gives $H$. This is in general faster than $\fl=4$ but the matrix $U$ + is usually worse; it is heuristically smaller than with the default algorithm. + + When the matrix is dense and the dimension is large (bigger than 100, say), + $\fl = 4$ will be fastest. When $M$ has maximal rank, then + \bprog + H = mathnfmod(M, matdetint(M)) + @eprog\noindent will be even faster. You can then recover $U$ as $M^{-1}H$. + + \bprog + ? M = matrix(3,4,i,j,random([-5,5])) + %1 = + [ 0 2 3 0] + + [-5 3 -5 -5] + + [ 4 3 -5 4] + + ? [H,U] = mathnf(M, 1); + ? U + %3 = + [-1 0 -1 0] + + [ 0 5 3 2] + + [ 0 3 1 1] + + [ 1 0 0 0] + + ? H + %5 = + [19 9 7] + + [ 0 9 1] + + [ 0 0 1] + + ? M*U + %6 = + [0 19 9 7] + + [0 0 9 1] + + [0 0 0 1] + @eprog + + For convenience, $M$ is allowed to be a \typ{VEC}, which is then + automatically converted to a \typ{MAT}, as per the \tet{Mat} function. + For instance to solve the generalized extended gcd problem, one may use + \bprog + ? v = [116085838, 181081878, 314252913,10346840]; + ? [H,U] = mathnf(v, 1); + ? U + %2 = + [ 103 -603 15 -88] + + [-146 13 -1208 352] + + [ 58 220 678 -167] + + [-362 -144 381 -101] + ? v*U + %3 = [0, 0, 0, 1] + @eprog\noindent This also allows to input a matrix as a \typ{VEC} of + \typ{COL}s of the same length (which \kbd{Mat} would concatenate to + the \typ{MAT} having those columns): + \bprog + ? v = [[1,0,4]~, [3,3,4]~, [0,-4,-5]~]; mathnf(v) + %1 = + [47 32 12] + + [ 0 1 0] + + [ 0 0 1] + @eprog +Variant: Also available are \fun{GEN}{hnf}{GEN M} ($\fl=0$) and + \fun{GEN}{hnfall}{GEN M} ($\fl=1$). To reduce \emph{huge} relation matrices + (sparse with small entries, say dimension $400$ or more), you can use the + pair \kbd{hnfspec} / \kbd{hnfadd}. Since this is quite technical and the + calling interface may change, they are not documented yet. Look at the code + in \kbd{basemath/hnf\_snf.c}. + +Function: mathnfmod +Class: basic +Section: linear_algebra +C-Name: hnfmod +Prototype: GG +Help: mathnfmod(x,d): (upper triangular) Hermite normal form of x, basis for + the lattice formed by the columns of x, where d is a multiple of the + nonzero determinant of this lattice. +Doc: if $x$ is a (not necessarily square) matrix of + maximal rank with integer entries, and $d$ is a multiple of the (nonzero) + determinant of the lattice spanned by the columns of $x$, finds the + \emph{upper triangular} \idx{Hermite normal form} of $x$. + + If the rank of $x$ is equal to its number of rows, the result is a square + matrix. In general, the columns of the result form a basis of the lattice + spanned by the columns of $x$. Even when $d$ is known, this is in general + slower than \kbd{mathnf} but uses much less memory. + +Function: mathnfmodid +Class: basic +Section: linear_algebra +C-Name: hnfmodid +Prototype: GG +Help: mathnfmodid(x,d): (upper triangular) Hermite normal form of x + concatenated with matdiagonal(d). +Doc: outputs the (upper triangular) + \idx{Hermite normal form} of $x$ concatenated with the diagonal + matrix with diagonal $d$. Assumes that $x$ has integer entries. + Variant: if $d$ is an integer instead of a vector, concatenate $d$ times the + identity matrix. + \bprog + ? m=[0,7;-1,0;-1,-1] + %1 = + [ 0 7] + + [-1 0] + + [-1 -1] + ? mathnfmodid(m, [6,2,2]) + %2 = + [2 1 1] + + [0 1 0] + + [0 0 1] + ? mathnfmodid(m, 10) + %3 = + [10 7 3] + + [ 0 1 0] + + [ 0 0 1] + @eprog + +Function: mathouseholder +Class: basic +Section: linear_algebra +C-Name: mathouseholder +Prototype: GG +Help: mathouseholder(Q,v): applies a sequence Q of Householder transforms + to the vector or matrix v. +Doc: \sidx{Householder transform}applies a sequence $Q$ of Householder + transforms, as returned by \kbd{matqr}$(M,1)$ to the vector or matrix $v$. + \bprog + ? m = [2,1; 3,2]; \\ some random matrix + ? [Q,R] = matqr(m); + ? Q + %3 = + [-0.554... -0.832...] + + [-0.832... 0.554...] + + ? R + %4 = + [-3.605... -2.218...] + + [0 0.277...] + + ? v = [1, 2]~; \\ some random vector + ? Q * v + %6 = [-2.218..., 0.277...]~ + + ? [q,r] = matqr(m, 1); + ? exponent(r - R) \\ r is the same as R + %8 = -128 + ? q \\ but q has a different structure + %9 = [[0.0494..., [5.605..., 3]]]] + ? mathouseholder(q, v) \\ applied to v + %10 = [-2.218..., 0.277...]~ + @eprog\noindent The point of the Householder structure is that it efficiently + represents the linear operator $v \mapsto Q \* v$ in a more stable way + than expanding the matrix $Q$: + \bprog + ? m = mathilbert(20); v = vectorv(20,i,i^2+1); + ? [Q,R] = matqr(m); + ? [q,r] = matqr(m, 1); + ? \p100 + ? [q2,r2] = matqr(m, 1); \\ recompute at higher accuracy + ? exponent(R - r) + %5 = -127 + ? exponent(R - r2) + %6 = -127 + ? exponent(mathouseholder(q,v) - mathouseholder(q2,v)) + %7 = -119 + ? exponent(Q*v - mathouseholder(q2,v)) + %8 = 9 + @eprog\noindent We see that $R$ is OK with or without a flag to \kbd{matqr} + but that multiplying by $Q$ is considerably less precise than applying the + sequence of Householder transforms encoded by $q$. + +Function: matid +Class: basic +Section: linear_algebra +C-Name: matid +Prototype: L +Help: matid(n): identity matrix of order n. +Description: + (small):vec matid($1) +Doc: creates the $n\times n$ identity matrix. + +Function: matimage +Class: basic +Section: linear_algebra +C-Name: matimage0 +Prototype: GD0,L, +Help: matimage(x,{flag=0}): basis of the image of the matrix x. flag is + optional and can be set to 0 or 1, corresponding to two different algorithms. +Description: + (gen, ?0):vec image($1) + (gen, 1):vec image2($1) + (gen, #small) $"incorrect flag in matimage" + (gen, small):vec matimage0($1, $2) +Doc: gives a basis for the image of the + matrix $x$ as columns of a matrix. A priori the matrix can have entries of + any type. If $\fl=0$, use standard Gauss pivot. If $\fl=1$, use + \kbd{matsupplement} (much slower: keep the default flag!). +Variant: Also available is \fun{GEN}{image}{GEN x} ($\fl=0$). + +Function: matimagecompl +Class: basic +Section: linear_algebra +C-Name: imagecompl +Prototype: G +Help: matimagecompl(x): vector of column indices not corresponding to the + indices given by the function matimage. +Description: + (gen):vecsmall imagecompl($1) +Doc: gives the vector of the column indices which + are not extracted by the function \kbd{matimage}, as a permutation + (\typ{VECSMALL}). Hence the number of + components of \kbd{matimagecompl(x)} plus the number of columns of + \kbd{matimage(x)} is equal to the number of columns of the matrix $x$. + +Function: matimagemod +Class: basic +Section: linear_algebra +C-Name: matimagemod +Prototype: GGD& +Help: matimagemod(x,d,&U): basis of the image of the matrix x modulo d. +Doc: gives a Howell basis (unique representation for submodules + of~$(\Z/d\Z)^{n}$) + for the image of the matrix $x$ modulo $d$ as columns of a matrix $H$. The + matrix $x$ must have \typ{INT} entries, and $d$ can be an arbitrary positive + integer. If $U$ is present, set it to a matrix such that~$AU = H$. + + \bprog + ? A = [2,1;0,2]; + ? matimagemod(A,6,&U) + %2 = + [1 0] + + [0 2] + + ? U + %3 = + [5 1] + + [3 4] + + ? (A*U)%6 + %4 = + [1 0] + + [0 2] + @eprog + + \misctitle{Caveat} In general the number of columns of the Howell form is not + the minimal number of generators of the submodule. Example: + + \bprog + ? matimagemod([1;2],4) + %5 = + [2 1] + + [0 2] + @eprog + + \misctitle{Caveat 2} In general the matrix $U$ is not invertible, even if~$A$ + and~$H$ have the same size. Example: + + \bprog + ? matimagemod([4,1;0,4],8,&U) + %6 = + [2 1] + + [0 4] + + ? U + %7 = + [0 0] + + [2 1] + @eprog + +Function: matindexrank +Class: basic +Section: linear_algebra +C-Name: indexrank +Prototype: G +Help: matindexrank(M): gives two extraction vectors (rows and columns) for + the matrix M such that the extracted matrix is square of maximal rank. +Description: + (gen):vecvecsmall indexrank($1) +Doc: $M$ being a matrix of rank $r$, returns a vector with two + \typ{VECSMALL} components $y$ and $z$ of length $r$ giving a list of rows + and columns respectively (starting from 1) such that the extracted matrix + obtained from these two vectors using $\tet{vecextract}(M,y,z)$ is + invertible. The vectors $y$ and $z$ are sorted in increasing order. + +Function: matintersect +Class: basic +Section: linear_algebra +C-Name: intersect +Prototype: GG +Help: matintersect(x,y): intersection of the vector spaces whose bases are + the columns of x and y. +Doc: $x$ and $y$ being two matrices with the same number of rows, finds a + basis of the vector space equal to the intersection of the spaces spanned by + the columns of $x$ and $y$ respectively. For efficiency, the columns of $x$ + (resp.~$y$) should be independent. + + The faster function \tet{idealintersect} can be used to intersect + fractional ideals (projective $\Z_{K}$ modules of rank $1$); the slower but + more general function \tet{nfhnf} can be used to intersect general + $\Z_{K}$-modules. + +Function: matinverseimage +Class: basic +Section: linear_algebra +C-Name: inverseimage +Prototype: GG +Help: matinverseimage(x,y): an element of the inverse image of the vector y + by the matrix x if one exists, the empty vector otherwise. +Doc: given a matrix $x$ and + a column vector or matrix $y$, returns a preimage $z$ of $y$ by $x$ if one + exists (i.e such that $x z = y$), an empty vector or matrix otherwise. The + complete inverse image is $z + \text{Ker} x$, where a basis of the kernel of + $x$ may be obtained by \kbd{matker}. + \bprog + ? M = [1,2;2,4]; + ? matinverseimage(M, [1,2]~) + %2 = [1, 0]~ + ? matinverseimage(M, [3,4]~) + %3 = []~ \\@com no solution + ? matinverseimage(M, [1,3,6;2,6,12]) + %4 = + [1 3 6] + + [0 0 0] + ? matinverseimage(M, [1,2;3,4]) + %5 = [;] \\@com no solution + ? K = matker(M) + %6 = + [-2] + + [1] + @eprog + +Function: matinvmod +Class: basic +Section: linear_algebra +C-Name: matinvmod +Prototype: GG +Help: matinvmod(x,d): left inverse of the matrix x modulo d. +Doc: computes a left inverse of the matrix~$x$ modulo~$d$. The matrix $x$ must + have \typ{INT} entries, and $d$ can be an arbitrary positive integer. + + \bprog + ? A = [3,1,2;1,2,1;3,1,1]; + ? U = matinvmod(A,6) + %2 = + [1 1 3] + + [2 3 5] + + [1 0 5] + + ? (U*A)%6 + %3 = + [1 0 0] + + [0 1 0] + + [0 0 1] + ? matinvmod(A,5) + *** at top-level: matinvmod(A,5) + *** ^-------------- + *** matinvmod: impossible inverse in gen_inv: 0. + @eprog + +Function: matisdiagonal +Class: basic +Section: linear_algebra +C-Name: isdiagonal +Prototype: iG +Help: matisdiagonal(x): true(1) if x is a diagonal matrix, false(0) + otherwise. +Doc: returns true (1) if $x$ is a diagonal matrix, false (0) if not. + +Function: matker +Class: basic +Section: linear_algebra +C-Name: matker0 +Prototype: GD0,L, +Help: matker(x,{flag=0}): basis of the kernel of the matrix x. flag is + optional, and may be set to 0: default; nonzero: x is known to have + integral entries. +Description: + (gen, ?0):vec ker($1) + (gen, 1):vec ZM_ker($1) + (gen, #small) $"incorrect flag in matker" + (gen, small):vec matker0($1, $2) +Doc: gives a basis for the kernel of the matrix $x$ as columns of a matrix. + The matrix can have entries of any type, provided they are compatible with + the generic arithmetic operations ($+$, $\times$ and $/$). + + If $x$ is known to have integral entries, set $\fl=1$. +Variant: Also available are \fun{GEN}{ker}{GEN x} ($\fl=0$), + \fun{GEN}{ZM_ker}{GEN x} ($\fl=1$). + +Function: matkerint +Class: basic +Section: linear_algebra +C-Name: matkerint0 +Prototype: GD0,L, +Help: matkerint(x,{flag=0}): LLL-reduced Z-basis of the kernel of the matrix + x with integral entries; flag is deprecated, kept for backward compatibility. +Doc: gives an \idx{LLL}-reduced $\Z$-basis + for the lattice equal to the kernel of the matrix $x$ with rational entries. + \fl{} is deprecated, kept for backward compatibility. The function + \kbd{matsolvemod} allows to solve more general linear systems over $\Z$. +Variant: Use directly \fun{GEN}{kerint}{GEN x} if $x$ is known to have + integer entries, and \tet{Q_primpart} first otherwise. + +Function: matkermod +Class: basic +Section: linear_algebra +C-Name: matkermod +Prototype: GGD& +Help: matkermod(x,d,&im): basis of the kernel of the matrix x modulo d. +Doc: gives a Howell basis (unique representation for submodules + of~$(\Z/d\Z)^{n}$, + cf. \kbd{matimagemod}) for the kernel of the matrix $x$ modulo $d$ as columns + of a matrix. The matrix $x$ must have \typ{INT} entries, and $d$ can be an + arbitrary positive integer. If $im$ is present, set it to a basis of the image + of~$x$ (which is computed on the way). + + \bprog + ? A = [1,2,3;5,1,4] + %1 = + [1 2 3] + + [5 1 4] + + ? K = matkermod(A,6) + %2 = + [2 1] + + [2 1] + + [0 3] + + ? (A*K)%6 + %3 = + [0 0] + + [0 0] + @eprog + +Function: matmuldiagonal +Class: basic +Section: linear_algebra +C-Name: matmuldiagonal +Prototype: GG +Help: matmuldiagonal(x,d): product of matrix x by diagonal matrix whose + diagonal coefficients are those of the vector d, equivalent but faster than + x*matdiagonal(d). +Doc: product of the matrix $x$ by the diagonal + matrix whose diagonal entries are those of the vector $d$. Equivalent to, + but much faster than $x*\kbd{matdiagonal}(d)$. + +Function: matmultodiagonal +Class: basic +Section: linear_algebra +C-Name: matmultodiagonal +Prototype: GG +Help: matmultodiagonal(x,y): product of matrices x and y, knowing that the + result will be a diagonal matrix. Much faster than general multiplication in + that case. +Doc: product of the matrices $x$ and $y$ assuming that the result is a + diagonal matrix. Much faster than $x*y$ in that case. The result is + undefined if $x*y$ is not diagonal. + +Function: matpascal +Class: basic +Section: linear_algebra +C-Name: matqpascal +Prototype: LDG +Help: matpascal(n,{q}): Pascal triangle of order n if q is omitted. q-Pascal + triangle otherwise. +Doc: creates as a matrix the lower triangular + \idx{Pascal triangle} of order $x+1$ (i.e.~with binomial coefficients + up to $x$). If $q$ is given, compute the $q$-Pascal triangle (i.e.~using + $q$-binomial coefficients). +Variant: Also available is \fun{GEN}{matpascal}{GEN x}. + +Function: matpermanent +Class: basic +Section: linear_algebra +C-Name: matpermanent +Prototype: G +Help: matpermanent(x): permanent of the matrix x. +Doc: permanent of the square matrix $x$ using Ryser's formula in Gray code + order. + \bprog + ? n = 20; m = matrix(n,n,i,j, i!=j); + ? matpermanent(m) + %2 = 895014631192902121 + ? n! * sum(i=0,n, (-1)^i/i!) + %3 = 895014631192902121 + @eprog\noindent This function runs in time $O(2^{n} n)$ for a matrix of size + $n$ and is not implemented for $n$ large. + +Function: matqr +Class: basic +Section: linear_algebra +C-Name: matqr +Prototype: GD0,L,p +Help: matqr(M,{flag=0}): returns [Q,R], the QR-decomposition of the square + invertible matrix M. If flag=1, Q is given as a sequence of Householder + transforms (faster and stabler). +Doc: returns $[Q,R]$, the \idx{QR-decomposition} of the square invertible + matrix $M$ with real entries: $Q$ is orthogonal and $R$ upper triangular. If + $\fl=1$, the orthogonal matrix is returned as a sequence of Householder + transforms: applying such a sequence is stabler and faster than + multiplication by the corresponding $Q$ matrix.\sidx{Householder transform} + More precisely, if + \bprog + [Q,R] = matqr(M); + [q,r] = matqr(M, 1); + @eprog\noindent then $r = R$ and \kbd{mathouseholder}$(q, M)$ is + (close to) $R$; furthermore + \bprog + mathouseholder(q, matid(#M)) == Q~ + @eprog\noindent the inverse of $Q$. This function raises an error if the + precision is too low or $x$ is singular. + +Function: matrank +Class: basic +Section: linear_algebra +C-Name: rank +Prototype: lG +Help: matrank(x): rank of the matrix x. +Doc: rank of the matrix $x$. + +Function: matreduce +Class: basic +Section: linear_algebra +C-Name: matreduce +Prototype: G +Help: matreduce(m): reduce the factorization matrix m to canonical form + (sorted first row with unique elements) + matrix. +Doc: let $m$ be a factorization matrix, i.e., a 2-column matrix whose + columns contains arbitrary ``generators'' and integer ``exponents'' + respectively. Returns the canonical form of $m$: the + first column is sorted with unique elements and the second one contains the + merged ``exponents'' (exponents of identical entries in the first column of + $m$ are added, rows attached to $0$ exponents are deleted). The generators are + sorted with respect to the universal \kbd{cmp} routine; in particular, this + function is the identity on true integer factorization matrices, but not on + other factorizations (in products of polynomials or maximal ideals, say). It + is idempotent. + + For convenience, this function also allows a vector $m$, which is handled as a + factorization with all exponents equal to $1$, as in \kbd{factorback}. + + \bprog + ? A=[x,2;y,4]; B=[x,-2; y,3; 3, 4]; C=matconcat([A,B]~) + %1 = + [x 2] + + [y 4] + + [x -2] + + [y 3] + + [3 4] + + ? matreduce(C) + %2 = + [3 4] + + [y 7] + + ? matreduce([x,x,y,x,z,x,y]) \\ vector argument + %3 = + [x 4] + + [y 2] + + [z 1] + @eprog\noindent The following one-line functions will list elements + occurring exactly once (resp. more than once) in the vector or list $v$: + \bprog + unique(v) = [ x[1] | x <- matreduce(v)~, x[2] == 1 ]; + duplicates(v) = [ x[1] | x <- matreduce(v)~, x[2] > 1 ]; + + ? v = [0,1,2,3,1,2]; + ? unique(v) + %2 = [0, 3] + + ? duplicates(v) + %3 = [1, 2] + @eprog + +Function: matrix +Class: basic +Section: linear_algebra +C-Name: matrice +Prototype: GDGDVDVDE +Help: matrix(m,{n=m},{X},{Y},{expr=0}): m x n matrix of expression expr, + where the row variable X goes from 1 to m and the column variable Y goes from + 1 to n. By default, fill with 0s. +Doc: creation of the + $m\times n$ matrix whose coefficients are given by the expression + \var{expr}. There are two formal parameters in \var{expr}, the first one + ($X$) corresponding to the rows, the second ($Y$) to the columns, and $X$ + goes from 1 to $m$, $Y$ goes from 1 to $n$. If one of the last 3 parameters + is omitted, fill the matrix with zeroes. If $n$ is omitted, return a + square $m \times m$ matrix. + %\syn{NO} + +Function: matrixqz +Class: basic +Section: linear_algebra +C-Name: matrixqz0 +Prototype: GDG +Help: matrixqz(A,{p=0}): if p>=0, transforms the rational or integral mxn (m>=n) + matrix A into an integral matrix with gcd of maximal determinants coprime to + p. If p=-1, finds a basis of the intersection with Z^n of the lattice spanned + by the columns of A. If p=-2, finds a basis of the intersection with Z^n of + the Q-vector space spanned by the columns of A. +Doc: $A$ being an $m\times n$ matrix in $M_{m,n}(\Q)$, let + $\text{Im}_{\Q} A$ (resp.~$\text{Im}_{\Z} A$) the $\Q$-vector space + (resp.~the $\Z$-module) spanned by the columns of $A$. This function has + varying behavior depending on the sign of $p$: + + If $p \geq 0$, $A$ is assumed to have maximal rank $n\leq m$. The function + returns a matrix $B\in M_{m,n}(\Z)$, with $\text{Im}_{\Q} B = + \text{Im}_{\Q} A$, + such that the GCD of all its $n\times n$ minors is coprime to + $p$; in particular, if $p = 0$ (default), this GCD is $1$. + + If $p=-1$, returns a basis of the lattice $\Z^{m} \cap \text{Im}_{\Z} A$. + + If $p=-2$, returns a basis of the lattice $\Z^{m} \cap \text{Im}_{\Q} A$. + + \misctitle{Caveat} ($p=-1$ or $-2$) For efficiency reason, we do not compute + the HNF of the resulting basis. + + \bprog + ? minors(x) = vector(#x[,1], i, matdet(x[^i,])); + ? A = [3,1/7; 5,3/7; 7,5/7]; minors(A) + %1 = [4/7, 8/7, 4/7] \\ determinants of all 2x2 minors + ? B = matrixqz(A) + %2 = + [3 1] + + [5 2] + + [7 3] + ? minors(%) + %3 = [1, 2, 1] \\ B integral with coprime minors + ? matrixqz(A,-1) + %4 = + [3 1] + + [5 3] + + [7 5] + + ? matrixqz(A,-2) + %5 = + [3 1] + + [5 2] + + [7 3] + + @eprog + +Function: matsize +Class: basic +Section: linear_algebra +C-Name: matsize +Prototype: G +Help: matsize(x): number of rows and columns of the vector/matrix x as a + 2-vector. +Doc: $x$ being a vector or matrix, returns a row vector + with two components, the first being the number of rows (1 for a row vector), + the second the number of columns (1 for a column vector). + +Function: matsnf +Class: basic +Section: linear_algebra +C-Name: matsnf0 +Prototype: GD0,L, +Help: matsnf(X,{flag=0}): Smith normal form (i.e. elementary divisors) of + the matrix X, expressed as a vector d; X must have integer or polynomial + entries. Binary digits of flag mean 1: returns + [u,v,d] where d=u*X*v, otherwise only the diagonal d is returned, + 4: removes all information corresponding to entries equal to 1 in d. +Doc: if $X$ is a (singular or nonsingular) matrix outputs the vector of + \idx{elementary divisors} of $X$, i.e.~the diagonal of the + \idx{Smith normal form} of $X$, normalized so that $d_{n} \mid d_{n-1} \mid + \ldots \mid d_{1}$. $X$ must have integer or polynomial entries; in the latter + case, $X$ must be a square matrix. + + The binary digits of \fl\ mean: + + 1 (complete output): if set, outputs $[U,V,D]$, where $U$ and $V$ are two + unimodular matrices such that $UXV$ is the diagonal matrix $D$. Otherwise + output only the diagonal of $D$. If $X$ is not a square matrix, then $D$ + will be a square diagonal matrix padded with zeros on the left or the top. + + 4 (cleanup): if set, cleans up the output. This means that elementary + divisors equal to $1$ will be deleted, i.e.~outputs a shortened vector $D'$ + instead of $D$. If complete output was required, returns $[U',V',D']$ so + that $U'XV' = D'$ holds. If this flag is set, $X$ is allowed to be of the + form `vector of elementary divisors' or $[U,V,D]$ as would normally be + output with the cleanup flag unset. + + If $v$ is an output from \kbd{matsnf} and $p$ is a power of an irreducible + element, then \kbd{snfrank(v, p)} returns the $p$-rank of the attached + module. + + \bprog + ? X = [27,0; 0,3; 1,1; 0,0]; matsnf(X) + %1 = [0, 0, 3, 1] + ? [U,V,D] = v = matsnf(X, 1); U*X*V == D + %2 + ? U + %3 = + [0 0 0 1] + + [1 9 -27 0] + + [0 1 0 0] + + [0 0 1 0] + + ? V + %4 = + [-1 1] + + [ 1 0] + + ? snfrank(v, 3) + %5 = 3 + @eprog\noindent Continuing the same example after cleanup: + \bprog + ? [U,V,D] = v = matsnf(X, 1+4); U*X*V == D + %6 = 1 + + ? D + %7 = + [0] + + [0] + + [3] + + ? snfrank(v, 3) + %8 = 3 + + ? snfrank(v, 2) + %9 = 2 + @eprog + +Function: matsolve +Class: basic +Section: linear_algebra +C-Name: gauss +Prototype: GG +Help: matsolve(M,B): solution of MX=B (M matrix, B column vector or matrix). +Doc: Let $M$ be a left-invertible matrix and $B$ a column vector + such that there exists a solution $X$ to the system of linear equations + $MX = B$; return the (unique) solution $X$. This has the same effect as, but + is faster, than $M^{-1}*B$. Uses Dixon $p$-adic lifting method if $M$ and + $B$ are integral and Gaussian elimination otherwise. When there is no + solution, the function returns an $X$ such that $MX - B$ is nonzero + although it has at least $\#M$ zero entries: + \bprog + ? M = [1,2;3,4;5,6]; + ? B = [4,6,8]~; X = matsolve(M, B) + %2 = [-2, 3]~ + ? M*X == B + %3 = 1 + ? B = [1,2,4]~; X = matsolve(M, [1,2,4]~) + %4 = [0, 1/2]~ + ? M*X - B + %5 = [0, 0, -1]~ + @eprog\noindent Raises an exception if $M$ is not left-invertible, even if + there is a solution: + \bprog + ? M = [1,1;1,1]; matsolve(M, [1,1]~) + *** at top-level: matsolve(M,[1,1]~) + *** ^------------------ + *** matsolve: impossible inverse in gauss: [1, 1; 1, 1]. + @eprog\noindent The function also works when $B$ is a matrix and we return + the unique matrix solution $X$ provided it exists. Again, if there is no + solution, the function returns an $X$ such that $MX - B$ is nonzero + although it has at least $\#M$ zero rows. + +Function: matsolvemod +Class: basic +Section: linear_algebra +C-Name: matsolvemod +Prototype: GGGD0,L, +Help: matsolvemod(M,D,B,{flag=0}): one solution of system of congruences + MX=B mod D (M matrix, B and D column vectors). If (optional) flag is + nonzero return all solutions. +Doc: $M$ being any integral matrix, + $D$ a column vector of nonnegative integer moduli, and $B$ an integral + column vector, gives an integer solution to the system of congruences + $\sum_{i} m_{i,j}x_{j}\equiv b_{i}\pmod{d_{i}}$ if one exists, otherwise + returns the integer zero. Note that we explicitly allow $d_{i} = 0$ + corresponding to an equality in $\Z$. Shorthand notation: $B$ (resp.~$D$) + can be given as a single integer, in which case all the $b_{i}$ + (resp.~$d_{i}$) above are taken to be equal to $B$ + (resp.~$D$). Again, $D = 0$ solves the linear system of equations over $\Z$. + \bprog + ? M = [1,2;3,4]; + ? matsolvemod(M, [3,4]~, [1,2]~) + %2 = [10, 0]~ + ? matsolvemod(M, 3, 1) \\ M X = [1,1]~ over F_3 + %3 = [2, 1]~ + ? matsolvemod(M, [3,0]~, [1,2]~) \\ x + 2y = 1 (mod 3), 3x + 4y = 2 (in Z) + %4 = [6, -4]~ + ? matsolvemod(M, 0, [1,2]~) \\ no solution in Z for x + 2y = 1, 3x + 4y = 2 + @eprog + If $\fl=1$, all solutions are returned in the form of a two-component row + vector $[x,u]$, where $x$ is an integer solution to the system of + congruences and $u$ is a matrix whose columns give a basis of the homogeneous + system (so that all solutions can be obtained by adding $x$ to any linear + combination of columns of $u$). If no solution exists, returns zero. +Variant: Also available are \fun{GEN}{gaussmodulo}{GEN M, GEN D, GEN B} + ($\fl=0$) and \fun{GEN}{gaussmodulo2}{GEN M, GEN D, GEN B} ($\fl=1$). + +Function: matsupplement +Class: basic +Section: linear_algebra +C-Name: suppl +Prototype: G +Help: matsupplement(x): supplement the columns of the matrix x to an + invertible matrix. +Doc: assuming that the columns of the matrix $x$ + are linearly independent (if they are not, an error message is issued), finds + a square invertible matrix whose first columns are the columns of $x$, + i.e.~supplement the columns of $x$ to a basis of the whole space. + \bprog + ? matsupplement([1;2]) + %1 = + [1 0] + + [2 1] + @eprog + Raises an error if $x$ has 0 columns, since (due to a long standing design + bug), the dimension of the ambient space (the number of rows) is unknown in + this case: + \bprog + ? matsupplement(matrix(2,0)) + *** at top-level: matsupplement(matrix + *** ^-------------------- + *** matsupplement: sorry, suppl [empty matrix] is not yet implemented. + @eprog + +Function: mattranspose +Class: basic +Section: linear_algebra +C-Name: gtrans +Prototype: G +Help: mattranspose(x): x~ = transpose of x. +Doc: transpose of $x$ (also $x\til$). + This has an effect only on vectors and matrices. + +Function: max +Class: basic +Section: operators +C-Name: gmax +Prototype: GG +Help: max(x,y): maximum of x and y. +Description: + (small, small):small maxss($1, $2) + (small, int):int gmaxsg($1, $2) + (int, small):int gmaxgs($1, $2) + (int, int):int gmax($1, $2) + (small, mp):mp gmaxsg($1, $2) + (mp, small):mp gmaxgs($1, $2) + (mp, mp):mp gmax($1, $2) + (small, gen):gen gmaxsg($1, $2) + (gen, small):gen gmaxgs($1, $2) + (gen, gen):gen gmax($1, $2) +Doc: creates the maximum of $x$ and $y$ when they can be compared. + +Function: mfDelta +Class: basic +Section: modular_forms +C-Name: mfDelta +Prototype: +Help: mfDelta(): mf corresponding to the Ramanujan Delta function. +Doc: mf structure corresponding to the Ramanujan Delta function $\Delta$. + \bprog + ? mfcoefs(mfDelta(),4) + %1 = [0, 1, -24, 252, -1472] + @eprog + +Function: mfEH +Class: basic +Section: modular_forms +C-Name: mfEH +Prototype: G +Help: mfEH(k): k>0 being in 1/2+Z, mf corresponding to the Cohen-Eisenstein + series H_k of weight k on G_0(4). +Doc: $k$ being in $1/2+\Z_{\geq 0}$, return the mf structure corresponding to + the Cohen-Eisenstein series $H_{k}$ of weight $k$ on $\Gamma_{0}(4)$. + \bprog + ? H = mfEH(13/2); mfcoefs(H,4) + %1 = [691/32760, -1/252, 0, 0, -2017/252] + @eprog The coefficients of $H$ are given by the Cohen-Hurwitz function + $H(k-1/2,N)$ and can be obtained for moderately large values of $N$ (the + algorithm uses $\tilde{O}(N)$ time): + \bprog + ? mfcoef(H,10^5+1) + time = 55 ms. + %2 = -12514802881532791504208348 + ? mfcoef(H,10^7+1) + time = 6,044 ms. + %3 = -1251433416009877455212672599325104476 + @eprog + +Function: mfEk +Class: basic +Section: modular_forms +C-Name: mfEk +Prototype: L +Help: mfEk(k): mf corresponding to the standard Eisenstein series + E_k for nonnegative even integer k. +Doc: k being an even nonnegative integer, return the mf structure + corresponding to the standard Eisenstein series $E_{k}$. + \bprog + ? mfcoefs(mfEk(8), 4) + %1 = [1, 480, 61920, 1050240, 7926240] + @eprog + +Function: mfTheta +Class: basic +Section: modular_forms +C-Name: mfTheta +Prototype: DG +Help: mfTheta({psi=1}): the unary theta function corresponding to the primitive + Dirichlet character psi, hence of weight 1/2 if psi is even, of weight 3/2 + if psi is odd. +Doc: the unary theta function corresponding to the primitive Dirichlet + character $\psi$. Its level is $4 F(\psi)^{2}$ and its weight is + $1 - \psi(-1)/2$. + \bprog + ? Ser(mfcoefs(mfTheta(),30)) + %1 = 1 + 2*x + 2*x^4 + 2*x^9 + 2*x^16 + 2*x^25 + O(x^31) + + ? f = mfTheta(8); Ser(mfcoefs(f,30)) + %2 = 2*x - 2*x^9 - 2*x^25 + O(x^31) + ? mfparams(f) + %3 = [256, 1/2, 8, y, t + 1] + + ? g = mfTheta(-8); Ser(mfcoefs(g,30)) + %4 = 2*x + 6*x^9 - 10*x^25 + O(x^31) + ? mfparams(g) + %5 = [256, 3/2, 8, y, t + 1] + + ? h = mfTheta(Mod(2,5)); mfparams(h) + %6 = [100, 3/2, Mod(7, 20), y, t^2 + 1] + @eprog + +Function: mfatkin +Class: basic +Section: modular_forms +C-Name: mfatkin +Prototype: GG +Help: mfatkin(mfatk,f): Given an mfatk output by mfatk = mfatkininit(mf,Q) + and a modular form f belonging to the space mf, returns the modular form + g = C*f|W_Q where C = mfatk[3] is a normalizing constant so that g + has the same field of coefficients as f; mfatk[1] = mf2 (or 0 if mf2=mf) + which is the space to which g belongs. +Doc: Given a \kbd{mfatk} output by \kbd{mfatk = mfatkininit(mf,Q)} and + a modular form $f$ belonging to the pace \kbd{mf}, returns the modular + form $g = C \times f|W_{Q}$, where $C = \kbd{mfatk[3]}$ is a normalizing + constant such that $g$ has the same field of coefficients as $f$; + \kbd{mfatk[3]} gives the constant $C$, and \kbd{mfatk[1]} gives + the modular form space to which $g$ belongs (or is set to $0$ if + it is \kbd{mf}). + \bprog + ? mf = mfinit([35,2],0); [f] = mfbasis(mf); + ? mfcoefs(f, 4) + %2 = [0, 3, -1, 0, 3] + ? mfatk = mfatkininit(mf,7); + ? g = mfatkin(mfatk, f); mfcoefs(g, 4) + %4 = [0, 1, -1, -2, 7] + ? mfatk = mfatkininit(mf,35); + ? g = mfatkin(mfatk, f); mfcoefs(g, 4) + %6 = [0, -3, 1, 0, -3] + @eprog + +Function: mfatkineigenvalues +Class: basic +Section: modular_forms +C-Name: mfatkineigenvalues +Prototype: GLp +Help: mfatkineigenvalues(mf,Q): given a modular form space mf + and a primitive divisor Q of the level of mf, outputs the corresponding + Atkin-Lehner eigenvalues on the new space, grouped by orbit. +Doc: Given a modular form space \kbd{mf} of integral weight $k$ and a primitive + divisor $Q$ of the level $N$ of \kbd{mf}, outputs the Atkin--Lehner + eigenvalues of $w_{Q}$ on the new space, grouped by orbit. If the Nebentypus + $\chi$ of \kbd{mf} is a + (trivial or) quadratic character defined modulo $N/Q$, the result is rounded + and the eigenvalues are $\pm i^{k}$. + \bprog + ? mf = mfinit([35,2],0); mffields(mf) + %1 = [y, y^2 - y - 4] \\ two orbits, dimension 1 and 2 + ? mfatkineigenvalues(mf,5) + %2 = [[1], [-1, -1]] + ? mf = mfinit([12,7,Mod(3,4)],0); + ? mfatkineigenvalues(mf,3) + %4 = [[I, -I, -I, I, I, -I]] \\ one orbit + @eprog + To obtain the eigenvalues on a larger space than the new space, + e.g., the full space, you can directly call \kbd{[mfB,M,C]=mfatkininit} and + compute the eigenvalues as the roots of the characteristic polynomial of + $M/C$, by dividing the roots of \kbd{charpoly(M)} by $C$. Note that the + characteristic polynomial is computed exactly since $M$ has coefficients in + $\Q(\chi)$, whereas $C$ may be given by a complex number. If the coefficients + of the characteristic polynomial are polmods modulo $T$ they must be embedded + to $\C$ first using \kbd{subst(lift(), t, exp(2*I*Pi/n))}, when $T$ is + \kbd{poliscyclo(n)}; note that $T = \kbd{mf.mod}$. + +Function: mfatkininit +Class: basic +Section: modular_forms +C-Name: mfatkininit +Prototype: GLp +Help: mfatkininit(mf,Q): initializes data necessary for working + with Atkin--Lehner operators W_Q, for now only the function mfatkin. + The result is a 4-component vector [mfB, MC, C, mf] where mfB is either + 0 or the possibly different modular form space to which F|W_Q will belong + (this does not depend on F in mf); MC is the matrix of W_Q on the basis of mf + multiplied by a normalizing constant C. +Doc: given a modular form space with parameters $N,k,\chi$ and a + primitive divisor $Q$ of the level $N$, initializes data necessary for + working with the Atkin--Lehner operator $W_{Q}$, for now only the function + \kbd{mfatkin}. We write $\chi \sim \chi_{Q} \chi_{N/Q}$ where + the two characters are primitive with (coprime) conductors dividing + $Q$ and $N/Q$ respectively. For $F\in M_{k}(\Gamma_{0}(N),\chi)$, + the form $F | W_{Q}$ still has level $N$ and weight $k$ but its + Nebentypus may no longer be $\chi$: it becomes + $\overline{\chi_{Q}} \chi_{N/Q})$ + if $k$ is integral and $\overline{\chi_{Q}} \chi_{N/Q})(4Q/\cdot)$ if not. + + The result is a technical 4-component vector \kbd{[mfB, MC, C, mf]}, where + + \item \kbd{mfB} encodes the modular form space to which + $F|W_{Q}$ belongs when $F \in M_{k}(\Gamma_{0}(N), \chi)$: an \kbd{mfinit} + corresponding to a new Nebentypus or the integer $0$ when the character does + not change. This does not depend on $F$. + + \item \kbd{MC} is the matrix of $W_{Q}$ on the bases of \kbd{mf} and \kbd{mfB} + multiplied by a normalizing constant $C(k,\chi,Q)$. This matrix has polmod + coefficients in $\Q(\chi)$. + + \item \kbd{C} is the complex constant $C(k,\chi,Q)$. For $k$ + integral, let $A(k,\chi, Q) = Q^{\varepsilon}/g(\chi_{Q})$, where + $\varepsilon = 0$ for $k$ even and $1/2$ for $k$ odd and + where $g(\chi_{Q})$ is the Gauss sum attached to $\chi_{Q}$). (A similar, more + complicated, definition holds in half-integral weight depending on the parity + of $k - 1/2$.) Then if $M$ denotes the matrix of $W_{Q}$ on the bases + of \kbd{mf} and \kbd{mfB}, $A \cdot M$ has coefficients in $\Q(\chi)$. + If $A$ is rational, we let $C = 1$ and $C = A$ as a floating point complex + number otherwise, and finally $\kbd{MC} := M \cdot C$. + + \bprog + ? mf=mfinit([32,4],0); [mfB,MC,C]=mfatkininit(mf,32); MC + %1 = + [5/16 11/2 55/8] + + [ 1/8 0 -5/4] + + [1/32 -1/4 11/16] + + ? C + %2 = 1 + ? mf=mfinit([32,4,8],0); [mfB,MC,C]=mfatkininit(mf,32); MC + %3 = + [ 1/8 -7/4] + + [-1/16 -1/8] + ? C + %4 = 0.35355339059327376220042218105242451964 + ? algdep(C,2) \\ C = 1/sqrt(8) + %5 = 8*x^2 - 1 + @eprog + +Function: mfbasis +Class: basic +Section: modular_forms +C-Name: mfbasis +Prototype: GD4,L, +Help: mfbasis(NK,{space=4}): If NK=[N,k,CHI] as in mfinit, gives a basis of + the corresponding subspace of M_k(G_0(N),CHI). NK can also be the output of + mfinit, in which case space is ignored. To obtain the eigenforms use + mfeigenbasis. +Doc: If $NK=[N,k,\var{CHI}]$ as in \kbd{mfinit}, gives a basis of the + corresponding subspace of $M_{k}(\Gamma_{0}(N),\chi)$. $NK$ can also be the + output of \kbd{mfinit}, in which case \kbd{space} can be omitted. + To obtain the eigenforms, use \kbd{mfeigenbasis}. + + If \kbd{space} is a full space $M_{k}$, the output is the union of first, a + basis of the space of Eisenstein series, and second, a basis of the cuspidal + space. + \bprog + ? see(L) = apply(f->mfcoefs(f,3), L); + ? mf = mfinit([35,2],0); + ? see( mfbasis(mf) ) + %2 = [[0, 3, -1, 0], [0, -1, 9, -8], [0, 0, -8, 10]] + ? see( mfeigenbasis(mf) ) + %3 = [[0, 1, 0, 1], [Mod(0, z^2 - z - 4), Mod(1, z^2 - z - 4), \ + Mod(-z, z^2 - z - 4), Mod(z - 1, z^2 - z - 4)]] + ? mf = mfinit([35,2]); + ? see( mfbasis(mf) ) + %5 = [[1/6, 1, 3, 4], [1/4, 1, 3, 4], [17/12, 1, 3, 4], \ + [0, 3, -1, 0], [0, -1, 9, -8], [0, 0, -8, 10]] + ? see( mfbasis([48,4],0) ) + %6 = [[0, 3, 0, -3], [0, -3, 0, 27], [0, 2, 0, 30]] + @eprog + +Function: mfbd +Class: basic +Section: modular_forms +C-Name: mfbd +Prototype: GL +Help: mfbd(F,d): F being a generalized modular form, return B(d)(F), where + B(d) is the expanding operator tau -> d tau. +Doc: $F$ being a generalized modular form, return $B(d)(F)$, where $B(d)$ is + the expanding operator $\tau\mapsto d\tau$. + \bprog + ? D2=mfbd(mfDelta(),2); mfcoefs(D2, 6) + %1 = [0, 0, 1, 0, -24, 0, 252] + @eprog + +Function: mfbracket +Class: basic +Section: modular_forms +C-Name: mfbracket +Prototype: GGD0,L, +Help: mfbracket(F,G,{m=0}): compute the + m-th Rankin-Cohen bracket of the generalized modular forms F and G. +Doc: compute the $m$-th Rankin--Cohen bracket of the generalized modular + forms $F$ and $G$. + \bprog + ? E4 = mfEk(4); E6 = mfEk(6); + ? D1 = mfbracket(E4,E4,2); mfcoefs(D1,5)/4800 + %2 = [0, 1, -24, 252, -1472, 4830] + ? D2 = mfbracket(E4,E6,1); mfcoefs(D2,10)/(-3456) + %3 = [0, 1, -24, 252, -1472, 4830] + @eprog + +Function: mfcoef +Class: basic +Section: modular_forms +C-Name: mfcoef +Prototype: GL +Help: mfcoef(F,n): Compute the n-th Fourier coefficient a(n) of the + generalized modular form F. +Doc: Compute the $n$-th Fourier coefficient $a(n)$ of the generalized modular + form $F$. Note that this is the $n+1$-st component of the vector + \kbd{mfcoefs(F,n)} as well as the second component of \kbd{mfcoefs(F,1,n)}. + \bprog + ? mfcoef(mfDelta(),10) + %1 = -115920 + @eprog + +Function: mfcoefs +Class: basic +Section: modular_forms +C-Name: mfcoefs +Prototype: GLD1,L, +Help: mfcoefs(F,n,{d=1}): Compute the vector of coefficients + [a[0],a[d],...,a[nd]] of the modular form F. +Doc: Compute the vector of Fourier coefficients $[a[0],a[d],...,a[nd]]$ of the + generalized modular form $F$; $d$ must be positive and $d = 1$ by default. + \bprog + ? D = mfDelta(); + ? mfcoefs(D,10) + %2 = [0, 1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920] + ? mfcoefs(D,5,2) + %3 = [0, -24, -1472, -6048, 84480, -115920] + ? mfcoef(D,10) + %4 = -115920 + @eprog\noindent + This function also applies when $F$ is a modular form space as output by + \kbd{mfinit}; it then returns the matrix whose columns give the Fourier + expansions of the elements of \kbd{mfbasis}$(F)$: + \bprog + ? mf = mfinit([1,12]); + ? mfcoefs(mf,5) + %2 = + [691/65520 0] + + [ 1 1] + + [ 2049 -24] + + [ 177148 252] + + [ 4196353 -1472] + + [ 48828126 4830] + @eprog + +Function: mfconductor +Class: basic +Section: modular_forms +C-Name: mfconductor +Prototype: lGG +Help: mfconductor(mf,F): mf being output by mfinit and F a modular form, + gives the smallest level at which F is defined. +Doc: \kbd{mf} being output by \kbd{mfinit} for the cuspidal space and + $F$ a modular form, gives the smallest level at which $F$ is defined. + In particular, if $F$ is cuspidal and we write $F = \sum_{j} B(d_{j}) f_{j}$ + for new forms $f_{j}$ of level $N_{j}$ (see \kbd{mftonew}), then its conductor + is the least common multiple of the $d_{j} N_{j}$. + \bprog + ? mf=mfinit([96,6],1); vF = mfbasis(mf); mfdim(mf) + %1 = 72 + ? vector(10,i, mfconductor(mf, vF[i])) + %2 = [3, 6, 12, 24, 48, 96, 4, 8, 12, 16] + @eprog + +Function: mfcosets +Class: basic +Section: modular_forms +C-Name: mfcosets +Prototype: G +Help: mfcosets(N): list of right cosets of G_0(N)\G, i.e., matrices g_j in G + such that G = U G_0(N) g_j. The g_j are chosen in the form [a,b; c,d] with + c | N. +Doc: let $N$ be a positive integer. Return the list of right cosets of + $\Gamma_{0}(N) \bs \Gamma$, i.e., matrices $\gamma_{j} \in \Gamma$ such that + $\Gamma = \bigsqcup_{j} \Gamma_{0}(N) \gamma_{j}$. + The $\gamma_{j}$ are chosen in the form $[a,b;c,d]$ with $c \mid N$. + \bprog + ? mfcosets(4) + %1 = [[0, -1; 1, 0], [1, 0; 1, 1], [0, -1; 1, 2], [0, -1; 1, 3],\ + [1, 0; 2, 1], [1, 0; 4, 1]] + @eprog\noindent We also allow the argument $N$ to be a modular form space, + in which case it is replaced by the level of the space: + \bprog + ? M = mfinit([4, 12, 1], 0); mfcosets(M) + %2 = [[0, -1; 1, 0], [1, 0; 1, 1], [0, -1; 1, 2], [0, -1; 1, 3],\ + [1, 0; 2, 1], [1, 0; 4, 1]] + @eprog + + \misctitle{Warning} In the present implementation, the trivial coset is + represented by $[1,0;N,1]$ and is the last in the list. + +Function: mfcuspisregular +Class: basic +Section: modular_forms +C-Name: mfcuspisregular +Prototype: lGG +Help: mfcuspisregular(NK,cusp): In the space defined by NK = [N,k,CHI] or + NK = mf, determine if cusp in canonical format (oo or denominator + dividing N) is regular or not. +Doc: In the space defined by \kbd{NK = [N,k,CHI]} or \kbd{NK = mf}, + determine if \kbd{cusp} in canonical format (oo or denominator + dividing $N$) is regular or not. + \bprog + ? mfcuspisregular([4,3,-4],1/2) + %1 = 0 + @eprog + +Function: mfcusps +Class: basic +Section: modular_forms +C-Name: mfcusps +Prototype: G +Help: mfcusps(N): list of cusps of G_0(N) in the form a/b with b dividing N. +Doc: let $N$ be a positive integer. Return the list of cusps of $\Gamma_{0}(N)$ + in the form $a/b$ with $b\mid N$. + \bprog + ? mfcusps(24) + %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/8, 1/12, 1/24] + @eprog\noindent We also allow the argument $N$ to be a modular form space, + in which case it is replaced by the level of the space: + \bprog + ? M = mfinit([4, 12, 1], 0); mfcusps(M) + %2 = [0, 1/2, 1/4] + @eprog + +Function: mfcuspval +Class: basic +Section: modular_forms +C-Name: mfcuspval +Prototype: GGGb +Help: mfcuspval(mf,F,cusp): valuation of modular form F in the space mf at + cusp, which can be either oo or any rational number. The result is + either a rational number or oo if F is zero. Let chi be the Nebentypus of + the space mf; if Q(F) != Q(chi), return the vector of valuations attached to + the [Q(F):Q(chi)] complex embeddings of F. +Doc: valuation of modular form $F$ in the space \kbd{mf} at + \kbd{cusp}, which can be either $\infty$ or any rational number. The + result is either a rational number or $\infty$ if $F$ is zero. Let + $\chi$ be the Nebentypus of the space \kbd{mf}; if $\Q(F) \neq \Q(\chi)$, + return the vector of valuations attached to the $[\Q(F):\Q(chi)]$ complex + embeddings of $F$. + \bprog + ? T=mfTheta(); mf=mfinit([12,1/2]); mfcusps(12) + %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/12] + ? apply(x->mfcuspval(mf,T,x), %1) + %2 = [0, 1/4, 0, 0, 1/4, 0] + ? mf=mfinit([12,6,12],1); F=mfbasis(mf)[5]; + ? apply(x->mfcuspval(mf,F,x),%1) + %4 = [1/12, 1/6, 1/2, 2/3, 1/2, 2] + ? mf=mfinit([12,3,-4],1); F=mfbasis(mf)[1]; + ? apply(x->mfcuspval(mf,F,x),%1) + %6 = [1/12, 1/6, 1/4, 2/3, 1/2, 1] + + ? mf = mfinit([625,2],0); [F] = mfeigenbasis(mf); mfparams(F) + %7 = [625, 2, 1, y^2 - y - 1, t - 1] \\ [Q(F):Q(chi)] = 2 + ? mfcuspval(mf, F, 1/25) + %8 = [1, 2] \\ one conjugate has valuation 1, and the other is 2 + ? mfcuspval(mf, F, 1/5) + %9 = [1/25, 1/25] + @eprog + +Function: mfcuspwidth +Class: basic +Section: modular_forms +C-Name: mfcuspwidth +Prototype: lGG +Help: mfcuspwidth(N,cusp): width of cusp in Gamma_0(N). +Doc: width of \kbd{cusp} in $\Gamma_{0}(N)$. + \bprog + ? mfcusps(12) + %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/12] + ? [mfcuspwidth(12,c) | c <- mfcusps(12)] + %2 = [12, 3, 4, 3, 1, 1] + ? mfcuspwidth(12, oo) + %3 = 1 + @eprog\noindent We also allow the argument $N$ to be a modular form space, + in which case it is replaced by the level of the space: + \bprog + ? M = mfinit([4, 12, 1], 0); mfcuspwidth(M, 1/2) + %4 = 1 + @eprog + +Function: mfderiv +Class: basic +Section: modular_forms +C-Name: mfderiv +Prototype: GD1,L, +Help: mfderiv(F,{m=1}): m-th formal derivative of the power series + corresponding to the generalized modular form F, with respect to the + differential operator q.d/dq (default m=1). +Doc: $m$-th formal derivative of the power series corresponding to + the generalized modular form $F$, with respect to the differential operator + $qd/dq$ (default $m=1$). + \bprog + ? D=mfDelta(); + ? mfcoefs(D, 4) + %2 = [0, 1, -24, 252, -1472] + ? mfcoefs(mfderiv(D), 4) + %3 = [0, 1, -48, 756, -5888] + @eprog + +Function: mfderivE2 +Class: basic +Section: modular_forms +C-Name: mfderivE2 +Prototype: GD1,L, +Help: mfderivE2(F,{m=1}): compute the Serre derivative (q.d/dq)F - kE_2F/12 + of the generalized modular form F of weight k; and if m > 1, the m-th iterate. +Doc: compute the Serre derivative $(q \* d/dq)F - kE_{2}F/12$ + of the generalized modular form $F$, which has weight $k+2$; + if $F$ is a true modular form, then its Serre derivative is also modular. + If $m>1$, compute the $m$-th iterate, of weight $k + 2m$. + \bprog + ? mfcoefs(mfderivE2(mfEk(4)),5)*(-3) + %1 = [1, -504, -16632, -122976, -532728] + ? mfcoefs(mfEk(6),5) + %2 = [1, -504, -16632, -122976, -532728] + @eprog + +Function: mfdescribe +Class: basic +Section: modular_forms +C-Name: mfdescribe +Prototype: GD& +Help: mfdescribe(F,{&G}): gives a human-readable description of F, which is + either a modular form space or a modular form. If the address of G is given, + puts into G the vector of parameters of the outmost operator defining F. +Doc: gives a human-readable description of $F$, which is either a modular + form space or a generalized modular form. If the address of $G$ is given, + puts into $G$ the vector of parameters of the outermost operator defining $F$; + this vector is empty if $F$ is a leaf (an atomic object such as + \kbd{mfDelta()}, not defined in terms of other forms) or a modular form space. + \bprog + ? E1 = mfeisenstein(4,-3,-4); mfdescribe(E1) + %1 = "F_4(-3, -4)" + ? E2 = mfeisenstein(3,5,-7); mfdescribe(E2) + %2 = "F_3(5, -7)" + ? E3 = mfderivE2(mfmul(E1,E2), 3); mfdescribe(E3,&G) + %3 = "DERE2^3(MUL(F_4(-3, -4), F_3(5, -7)))" + ? mfdescribe(G[1][1]) + %4 = "MUL(F_4(-3, -4), F_3(5, -7))" + ? G[2] + %5 = 3 + ? for (i = 0, 4, mf = mfinit([37,4],i); print(mfdescribe(mf))); + S_4^new(G_0(37, 1)) + S_4(G_0(37, 1)) + S_4^old(G_0(37, 1)) + E_4(G_0(37, 1)) + M_4(G_0(37, 1)) + @eprog + +Function: mfdim +Class: basic +Section: modular_forms +C-Name: mfdim +Prototype: GD4,L, +Help: mfdim(NK,{space=4}): If NK=[N,k,CHI] as in + mfinit, gives the dimension of the corresponding subspace of + M_k(G_0(N),chi). The subspace is described by a small integer 'space': 0 for + the newspace, 1 for the cuspidal space, 2 for the oldspace, 3 for the space + of Eisenstein series and 4 (default) for the full space M_k. + NK can also be the output of mfinit, in which case space must be omitted. +Doc: If $NK=[N,k,\var{CHI}]$ as in \kbd{mfinit}, gives the dimension of the + corresponding subspace of $M_{k}(\Gamma_{0}(N),\chi)$. $NK$ can also be the + output of \kbd{mfinit}, in which case space must be omitted. + + The subspace is described by the small integer \kbd{space}: $0$ for the + newspace $S_{k}^{\text{new}}(\Gamma_{0}(N),\chi)$, $1$ for the cuspidal + space $S_{k}$, $2$ for the oldspace $S_{k}^{\text{old}}$, $3$ for the space of + Eisenstein series $E_{k}$ and $4$ for the full space $M_{k}$. + + \misctitle{Wildcards} + As in \kbd{mfinit}, \var{CHI} may be the wildcard 0 + (all Galois orbits of characters); in this case, the output is a vector of + $[\var{order}, \var{conrey}, \var{dim}, \var{dimdih}]$ corresponding + to the nontrivial spaces, where + + \item \var{order} is the order of the character, + + \item \var{conrey} its Conrey label from which the character may be recovered + via \kbd{znchar}$(\var{conrey})$, + + \item \var{dim} the dimension of the corresponding space, + + \item \var{dimdih} the dimension of the subspace of dihedral forms + corresponding to Hecke characters if $k = 1$ (this is not implemented for + the old space and set to $-1$ for the time being) and 0 otherwise. + + The spaces are sorted by increasing order of the character; the characters are + taken up to Galois conjugation and the Conrey number is the minimal one among + Galois conjugates. In weight $1$, this is only implemented when + the space is 0 (newspace), 1 (cusp space), 2(old space) or 3(Eisenstein + series). + + \misctitle{Wildcards for sets of characters} \var{CHI} may be a set + of characters, and we return the set of $[\var{dim},\var{dimdih}]$. + + \misctitle{Wildcard for $M_{k}(\Gamma_{1}(N))$} + Additionally, the wildcard $\var{CHI} = -1$ is available in which case we + output the total dimension of the corresponding + subspace of $M_{k}(\Gamma_{1}(N))$. In weight $1$, this is not implemented + when the space is 4 (fullspace). + + \bprog + ? mfdim([23,2], 0) \\ new space + %1 = 2 + ? mfdim([96,6], 0) + %2 = 10 + ? mfdim([10^9,4], 3) \\ Eisenstein space + %1 = 40000 + ? mfdim([10^9+7,4], 3) + %2 = 2 + ? mfdim([68,1,-1],0) + %3 = 3 + ? mfdim([68,1,0],0) + %4 = [[2, Mod(67, 68), 1, 1], [4, Mod(47, 68), 1, 1]] + ? mfdim([124,1,0],0) + %5 = [[6, Mod(67, 124), 2, 0]] + @eprog + This last example shows that there exists a nondihedral form of weight 1 + in level 124. + +Function: mfdiv +Class: basic +Section: modular_forms +C-Name: mfdiv +Prototype: GG +Help: mfdiv(F,G): compute F/G for two modular forms F and G assuming + that the quotient will not have poles at infinity. If this is the + case, use mfshift before doing the division. +Doc: Given two generalized modular forms $F$ and $G$, compute $F/G$ assuming + that the quotient will not have poles at infinity. If this is the + case, use \kbd{mfshift} before doing the division. + \bprog + ? D = mfDelta(); \\ Delta + ? H = mfpow(mfEk(4), 3); + ? J = mfdiv(H, D) + *** at top-level: J=mfdiv(H,mfdeltac + *** ^-------------------- + *** mfdiv: domain error in mfdiv: ord(G) > ord(F) + ? J = mfdiv(H, mfshift(D,1)); + ? mfcoefs(J, 4) + %4 = [1, 744, 196884, 21493760, 864299970] + @eprog + +Function: mfeigenbasis +Class: basic +Section: modular_forms +C-Name: mfeigenbasis +Prototype: G +Help: mfeigenbasis(mf): vector of the eigenforms for the space mf. +Doc: vector of the eigenforms for the space \kbd{mf}. + The initial basis of forms computed by \kbd{mfinit} before splitting + is also available via \kbd{mfbasis}. + \bprog + ? mf = mfinit([26,2],0); + ? see(L) = for(i=1,#L,print(mfcoefs(L[i],6))); + ? see( mfeigenbasis(mf) ) + [0, 1, -1, 1, 1, -3, -1] + [0, 1, 1, -3, 1, -1, -3] + ? see( mfbasis(mf) ) + [0, 2, 0, -2, 2, -4, -4] + [0, -2, -4, 10, -2, 0, 8] + @eprog + The eigenforms are internally expressed as (algebraic) linear combinations of + \kbd{mfbasis(mf)} and it is very inefficient to compute many coefficients + of those forms individually: you should rather use \kbd{mfcoefs(mf)} + to expand the basis once and for all, then multiply by \kbd{mftobasis(mf,f)} + for the forms you're interested in: + \bprog + ? mf = mfinit([96,6],0); B = mfeigenbasis(mf); #B + %1 = 8; + ? vector(#B, i, mfcoefs(B[i],1000)); \\ expanded individually: slow + time = 7,881 ms. + ? M = mfcoefs(mf, 1000); \\ initialize once + time = 982 ms. + ? vector(#B, i, M * mftobasis(mf,B[i])); \\ then expand: much faster + time = 623 ms. + @eprog + + When the eigenforms are defined over an extension field of $\Q(\chi)$ for a + nonrational character, their coefficients are hard to read and you may want + to lift them or to express them in an absolute number field. In the + construction below $T$ defines $\Q(f)$ over $\Q$, $a$ is the image of the + generator \kbd{Mod}$(t, t^{2}+t+1)$ of $\Q(\chi)$ in $\Q(f)$ + and $y - ka$ is the image of the root $y$ of \kbd{f.mod}: + \bprog + ? mf = mfinit([31, 2, Mod(25,31)], 0); [f] = mfeigenbasis(mf); + ? f.mod + %2 = Mod(1, t^2 + t + 1)*y^2 + Mod(2*t + 2, t^2 + t + 1) + ? v = liftpol(mfcoefs(f,5)) + %3 = [0, 1, (-t - 1)*y - 1, t*y + (t + 1), (2*t + 2)*y + 1, t] + ? [T,a,k] = rnfequation(mf.mod, f.mod, 1) + %4 = [y^4 + 2*y^2 + 4, Mod(-1/2*y^2 - 1, y^4 + 2*y^2 + 4), 0] + ? liftpol(substvec(v, [t,y], [a, y-k*a])) + %5 = [0, 1, 1/2*y^3 - 1, -1/2*y^3 - 1/2*y^2 - y, -y^3 + 1, -1/2*y^2 - 1] + @eprog\noindent Beware that the meaning of $y$ has changed in the last line + is different: it now represents of root of $T$, no longer of \kbd{f.mod} + (the notions coincide if $k = 0$ as here but it will not always be the case). + This can be avoided with an extra variable substitution, for instance + \bprog + ? [T,a,k] = rnfequation(mf.mod, subst(f.mod,'y,'x), 1) + %6 = [x^4 + 2*x^2 + 4, Mod(-1/2*x^2 - 1, x^4 + 2*x^2 + 4), 0] + ? liftpol(substvec(v, [t,y], [a, x-k*a])) + %7 = [0, 1, 1/2*x^3 - 1, -1/2*x^3 - 1/2*x^2 - x, -x^3 + 1, -1/2*x^2 - 1] + @eprog + +Function: mfeigensearch +Class: basic +Section: modular_forms +C-Name: mfeigensearch +Prototype: GDG +Help: mfeigensearch(NK,{AP}): search for normalized rational eigen cuspforms + with quadratic characters given a few initial coefficients. The meaning of + the parameters is as follows: + + NK is of the form [N,k]: search given level N, weight k and quadratic + character; note that the character is uniquely determined by (N,k). + The level N can be replaced by a vector of allowed levels. + + AP is the search criterion, which can be omitted: a list of pairs + [...,[p,a_p],...], where a_p is either a t_INT (exact match) or a t_INTMOD + (match modulo the given integer). + + The result is a vector of newforms matching the search criteria, sorted by + increasing level. +Doc: search for a normalized rational eigen cuspform with quadratic + character given restrictions on a few initial coefficients. The meaning of + the parameters is as follows: + + \item \kbd{NK} governs the limits of the search: it is of the form + $[N,k]$: search for given level $N$, weight $k$ and quadratic + character; note that the character $(D/.)$ is uniquely determined by $(N,k)$. + The level $N$ can be replaced by a vector of allowed levels. + + \item \kbd{AP} is the search criterion, which can be omitted: a list of + pairs $[\ldots, [p,a_{p}], \ldots]$, where $p$ is a prime number and $a_{p}$ is + either a \typ{INT} (the $p$-th Fourier coefficient must match $a_{p}$ exactly) + or a \typ{INTMOD} \kbd{Mod}$(a,b)$ (the $p$-th coefficient must be congruent + to $a$ modulo $b$). + + The result is a vector of newforms $f$ matching the search criteria, sorted + by increasing level then increasing $|D|$. + \bprog + ? #mfeigensearch([[1..80],2], [[2,2],[3,-1]]) + %1 = 1 + ? #mfeigensearch([[1..80],2], [[2,2],[5,2]]) + %2 = 1 + ? v = mfeigensearch([[1..20],2], [[3,Mod(2,3)],[7,Mod(5,7)]]); #v + %3 = 1 + ? F=v[1]; [mfparams(F)[1], mfcoefs(F,15)] + %4 = [11, [0, 1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1]] + @eprog + +Function: mfeisenstein +Class: basic +Section: modular_forms +C-Name: mfeisenstein +Prototype: LDGDG +Help: mfeisenstein(k,{CHI1},{CHI2}): create the Eisenstein + E_k(CHI1,CHI2), where an omitted character is considered as trivial. +Doc: create the Eisenstein series $E_{k}(\chi_{1},\chi_{2})$, where $k \geq 1$, + $\chi_{i}$ are Dirichlet characters and an omitted character is considered as + trivial. This form belongs to ${\cal E}_{k}(\Gamma_{0}(N), \chi)$ with $\chi = + \chi_{1}\chi_{2}$ and $N$ is the product of the conductors of $\chi_{1}$ and + $\chi_{2}$. + \bprog + ? CHI = Mod(3,4); + ? E = mfeisenstein(3, CHI); + ? mfcoefs(E, 6) + %2 = [-1/4, 1, 1, -8, 1, 26, -8] + ? CHI2 = Mod(4,5); + ? mfcoefs(mfeisenstein(3,CHI,CHI2), 6) + %3 = [0, 1, -1, -10, 1, 25, 10] + ? mfcoefs(mfeisenstein(4,CHI,CHI), 6) + %4 = [0, 1, 0, -28, 0, 126, 0] + ? mfcoefs(mfeisenstein(4), 6) + %5 = [1/240, 1, 9, 28, 73, 126, 252] + @eprog\noindent Note that \kbd{mfeisenstein}$(k)$ is 0 for $k$ odd and + $-B_{k}/(2k) \cdot E_{k}$ for $k$ even, where + $$E_{k}(q) = 1 - (2k/B_{k})\sum_{n\geq 1} \sigma_{k-1}(n) q^{n}$$ + is the standard Eisenstein series. In other words it is normalized so that its + linear coefficient is $1$. + + \misctitle{Important note} This function is currently implemented only when + $\Q(\chi)$ is the field of definition of $E_{k}(\chi_{1},\chi_{2})$. If it is a + strict subfield, an error is raised: + \bprog + ? mfeisenstein(6, Mod(7,9), Mod(4,9)); + *** at top-level: mfeisenstein(6,Mod(7,9),Mod(4,9)) + *** ^--------------------------------- + *** mfeisenstein: sorry, mfeisenstein for these characters is not + *** yet implemented. + @eprog\noindent The reason for this is that each modular form is attached + to a modular form space $M_{k}(\Gamma_{0}(N),\chi)$. This is a $\C$-vector + space but it allows a basis of forms defined over $\Q(\chi)$ and is only + implemented as a $\Q(\chi)$-vector space: there is + in general no mechanism to take linear combinations of forms in the space + with coefficients belonging to a larger field. (Due to their importance, + eigenforms are the single exception to this restriction; for an eigenform + $F$, $\Q(F)$ is built on top of $\Q(\chi)$.) When the property $\Q(\chi) = + \Q(E_{k}(\chi_{1},\chi_{2})$ does not hold, we cannot express $E$ as a + $\Q(\chi)$-linear combination of the basis forms and many operations will + fail. For this reason, the construction is currently disabled. + +Function: mfembed +Class: basic +Section: modular_forms +C-Name: mfembed0 +Prototype: GDGp +Help: mfembed(f,{v}): + if v is omitted, f must be a modular form or a modular form + space with parameters [N,k,chi] and we return a vector of complex + embeddings of Q(f) or Q(chi), respectively. + + If v is given, it must be a scalar in Q(f), or a vector/matrix of such, + we apply the embeddings coefficientwise and return a vector of results. + Finally f can be replaced by a single embedding produced by mfembed(f) + and we apply that particular embedding to v. Note that, in our context, + Q(chi) has a single canonical embeding given by s: Mod(t, polcyclo(n,t)) + -> exp(2*I*Pi/n) and Q(f) has [Q(f):Q(chi)] induced embeddings attached + to the complex roots of s(P) where P = mfparams(f)[4], as ordered by + polroots. In the latter case, we only support an f with Q(f) = Q(chi) or + an eigenform produced by mfeigenbasis. +Doc: let $f$ be a generalized modular form with parameters $[N,k,\chi,P]$ (see + \kbd{mfparams}, we denote $\Q(\chi)$ the subfield of $\C$ generated by the + values of $\chi$ and $\Q(f)$ the field of definition of $f$. In this context + $\Q(\chi)$ has a single canonical complex embeding given by + $s: \kbd{Mod(t, polcyclo(n,t))} \mapsto \exp(2i\pi/n)$ and the number field + $\Q(f)$ has $[\Q(f):\Q(\chi)]$ induced embeddings attached to the complex + roots of the polynomial $s(P)$. If $\Q(f)$ is stricly larger than $\Q(\chi)$ + we only allow an $f$ which is an eigenform, produced by \kbd{mfeigenbasis}. + + This function is meant to create embeddings of $\Q(f)$ and/or apply them + to the object $v$, typically a vector of Fourier coefficients of $f$ + from \kbd{mfcoefs}. + + \item If $v$ is omitted and $f$ is a modular form as above, we return the + embedding of $\Q(\chi)$ if $\Q(\chi) = \Q(f)$ and a vector containing + $[\Q(f):\Q(\chi)]$ embeddings of $\Q(f)$ otherwise. + + \item If $v$ is given, it must be a scalar in $\Q(f)$, or a vector/matrix of + such, we apply the embeddings coefficientwise and return either + a single result if $\Q(f) = \Q(\chi)$ and a vector of $[\Q(f):\Q(\chi)]$ + results otherwise. + + \item Finally $f$ can be replaced by a single embedding produced by + \kbd{mfembed}$(f)$ ($v$ was omitted) and we apply that particular embedding + to $v$. + + \bprog + ? mf = mfinit([35,2,Mod(11,35)], 0); + ? [f] = mfbasis(mf); + ? f.mod \\@com $\Q(\chi) = \Q(\zeta_{3})$ + %3 = t^2 + t + 1 + ? v = mfcoefs(f,5); lift(v) \\@com coefficients in $\Q(\chi)$ + %4 = [0, 2, -2*t - 2, 2*t, 2*t, -2*t - 2] + ? mfembed(f, v) \\ single embedding + %5 = [0, 2, -1 - 1.7320...*I, -1 + 1.73205...*I, -1 + 1.7320...*I, ...] + + ? [F] = mfeigenbasis(mf); + ? mffields(mf) + %7 = [y^2 + Mod(-2*t, t^2 + t + 1)] \\@com $[\Q(f):\Q(\chi)] = 2$ + ? V = liftpol( mfcoefs(F,5) ); + %8 = [0, 1, y + (-t - 1), (t + 1)*y + t, (-2*t - 2)*y + t, -t - 1] + ? vall = mfembed(F, V); #vall + %9 = 2 \\ 2 embeddings, both applied to V + ? vall[1] \\ the first + %10 = [0, 1, -1.2071... - 2.0907...*I, 0.2071... - 0.3587...*I, ...] + ? vall[2] \\ and the second one + %11 = [0, 1, 0.2071... + 0.3587...*I, -1.2071... + 2.0907...*I, ...] + + ? vE = mfembed(F); #vE \\ same 2 embeddings + %12 = 2 + ? mfembed(vE[1], V) \\ apply first embedding to V + %13 = [0, 1, -1.2071... - 2.0907...*I, 0.2071... - 0.3587...*I, ...] + @eprog + + For convenience, we also allow a modular form space from \kbd{mfinit} + instead of $f$, corresponding to the single embedding of $\Q(\chi)$. + \bprog + ? [mfB,MC,C] = mfatkininit(mf,7); MC \\@com coefs in $\Q(\chi)$ + %13 = + [ Mod(2/7*t, t^2 + t + 1) Mod(-1/7*t - 2/7, t^2 + t + 1)] + + [Mod(-1/7*t - 2/7, t^2 + t + 1) Mod(2/7*t, t^2 + t + 1)] + + ? C \\ normalizing constant + %14 = 0.33863... - 0.16787*I + ? M = mfembed(mf, MC) / C \\ the true matrix for the action of w_7 + [-0.6294... + 0.4186...*I -0.3625... - 0.5450...*I] + + [-0.3625... - 0.5450...*I -0.6294... + 0.4186...*I] + + ? exponent(M*conj(M) - 1) \\ M * conj(M) is close to 1 + %16 = -126 + @eprog + +Function: mfeval +Class: basic +Section: modular_forms +C-Name: mfeval +Prototype: GGGb +Help: mfeval(mf,F,vtau): computes the numerical value of the modular form F + at the point vtau or the vector vtau of points in the completed + upper-half plane. +Doc: Computes the numerical value of the modular form $F$, belonging + to \var{mf}, at the complex number \kbd{vtau} or the vector \kbd{vtau} + of complex numbers in the completed upper-half plane. The result is given + with absolute error less than $2^{-B}$, where $B = \text{realbitprecision}$. + + If the field of definition $\Q(F)$ is larger than $\Q(\chi)$ then $F$ may be + embedded into $\C$ in $d=[\Q(F):\Q(\chi)]$ ways, in which case a vector of + the $d$ results is returned. + \bprog + ? mf = mfinit([11,2],0); F = mfbasis(mf)[1]; mfparams(F) + %1 = [11, 2, 1, y, t-1] \\ Q(F) = Q(chi) = Q + ? mfeval(mf,F,I/2) + %2 = 0.039405471130100890402470386372028382117 + ? mf = mfinit([35,2],0); F = mfeigenbasis(mf)[2]; mfparams(F) + %3 = [35, 2, 1, y^2 - y - 4, t - 1] \\ [Q(F) : Q(chi)] = 2 + ? mfeval(mf,F,I/2) + %4 = [0.045..., 0.0385...] \\ sigma_1(F) and sigma_2(F) at I/2 + ? mf = mfinit([12,4],1); F = mfbasis(mf)[1]; + ? mfeval(mf, F, 0.318+10^(-7)*I) + %6 = 3.379... E-21 + 6.531... E-21*I \\ instantaneous ! + @eprog\noindent In order to maximize the imaginary part of the argument, + the function computes $(f \mid_{k} \gamma)(\gamma^{-1}\cdot\tau)$ for a + suitable $\gamma$ not necessarily in $\Gamma_{0}(N)$ (in which case $f \mid + \gamma$ is evaluated using \kbd{mfslashexpansion}). + \bprog + ? T = mfTheta(); mf = mfinit(T); mfeval(mf,T,[0,1/2,1,oo]) + %1 = [1/2 - 1/2*I, 0, 1/2 - 1/2*I, 1] + @eprog + +Function: mffields +Class: basic +Section: modular_forms +C-Name: mffields +Prototype: G +Help: mffields(mf): If mf is output by mfinit, gives the + vector of polynomials defining each Galois orbit of the new space. +Doc: Given \kbd{mf} as output by \kbd{mfinit} with parameters + $(N,k,\chi)$, returns the vector of polynomials defining each Galois orbit of + newforms over $\Q(\chi)$. + \bprog + ? mf = mfinit([35,2],0); mffields(mf) + %1 = [y, y^2 - y - 4] + @eprog\noindent Here the character is trivial so $\Q(\chi) = \Q)$ and there + are 3 newforms: one is rational (corresponding to $y$), the other two are + conjugate and defined over the quadratic field $\Q[y]/(y^{2}-y-4)$. + + \bprog + ? [G,chi] = znchar(Mod(3,35)); + ? zncharconductor(G,chi) + %2 = 35 + ? charorder(G,chi) + %3 = 12 + ? mf = mfinit([35, 2, [G,chi]],0); mffields(mf) + %4 = [y, y] + @eprog Here the character is primitive of order 12 and the two newforms are + defined over $\Q(\chi) = \Q(\zeta_{12})$. + + \bprog + ? mf = mfinit([35, 2, Mod(13,35)],0); mffields(mf) + %3 = [y^2 + Mod(5*t, t^2 + 1)] + @eprog This time the character has order 4 and there are two conjugate + newforms over $\Q(\chi) = Q(i)$. + +Function: mffromell +Class: basic +Section: modular_forms +C-Name: mffromell +Prototype: G +Help: mffromell(E): E being an elliptic curve defined over Q given by an + integral model in ellinit format, computes a 3-component vector [mf,F,v], + where F is the newform corresponding to E by modularity, mf is the + newspace to which F belongs, and v gives the coefficients of F on + mfbasis(mf). +Doc: $E$ being an elliptic curve defined over $Q$ given by an + integral model in \kbd{ellinit} format, computes a 3-component vector + \kbd{[mf,F,v]}, where $F$ is the newform corresponding to $E$ by + modularity, \kbd{mf} is the newspace to which $F$ belongs, and + \kbd{v} gives the coefficients of $F$ on \kbd{mfbasis(mf)}. + \bprog + ? E = ellinit("26a1"); + ? [mf,F,co] = mffromell(E); + ? co + %2 = [3/4, 1/4]~ + ? mfcoefs(F, 5) + %3 = [0, 1, -1, 1, 1, -3] + ? ellan(E, 5) + %4 = [1, -1, 1, 1, -3] + @eprog + +Function: mffrometaquo +Class: basic +Section: modular_forms +C-Name: mffrometaquo +Prototype: GD0,L, +Help: mffrometaquo(eta,{flag=0}): modular form corresponding to the eta + quotient matrix eta. If the valuation v at infinity is fractional, returns 0. + If the eta quotient is not holomorphic but simply meromorphic, returns 0 if + flag=0; returns the eta quotient (divided by q to the power -v if v < 0, i.e., + with valuation 0) if flag is set. +Doc: modular form corresponding to the eta quotient matrix \kbd{eta}. + If the valuation $v$ at infinity is fractional, returns $0$. If the eta + quotient is not holomorphic but simply meromorphic, returns $0$ if + $\fl=0$; returns the eta quotient (divided by $q$ to the power $-v$ if + $v < 0$, i.e., with valuation $0$) if $\fl$ is set. + \bprog + ? mffrometaquo(Mat([1,1]),1) + %1 = 0 + ? mfcoefs(mffrometaquo(Mat([1,24])),6) + %2 = [0, 1, -24, 252, -1472, 4830, -6048] + ? mfcoefs(mffrometaquo([1,1;23,1]),10) + %3 = [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0] + ? F = mffrometaquo([1,2;2,-1]); mfparams(F) + %4 = [16, 1/2, 1, y, t - 1] + ? mfcoefs(F,10) + %5 = [1, -2, 0, 0, 2, 0, 0, 0, 0, -2, 0] + ? mffrometaquo(Mat([1,-24])) + %6 = 0 + ? f = mffrometaquo(Mat([1,-24]),1); mfcoefs(f,6) + %7 = [1, 24, 324, 3200, 25650, 176256, 1073720] + @eprog\noindent For convenience, a \typ{VEC} is also accepted instead of + a factorization matrix with a single row: + \bprog + ? f = mffrometaquo([1,24]); \\ also valid + @eprog + +Function: mffromlfun +Class: basic +Section: modular_forms +C-Name: mffromlfun +Prototype: Gp +Help: mffromlfun(L): L being an L-function representing a self-dual modular + form, return [NK,space,v] where mf=mfinit(NK,space) contains the form + and mftobasis(mf, v) + containing it and v is mftobasis(mf,f). +Doc: Let $L$ being an $L$-function in any of the \kbd{lfun} formats representing + a self-dual modular form (for instance an eigenform). Return + \kbd{[NK,space,v]} when \kbd{mf = mfinit(NK,space)} is the modular + form space containing the form and \kbd{mftobasis(mf, v)} will represent it + on the space basis. If $L$ has rational coefficients, this will be enough + to recognize the modular form in \var{mf}: + \bprog + ? L = lfuncreate(x^2+1); + ? lfunan(L,10) + %2 = [1, 1, 0, 1, 2, 0, 0, 1, 1, 2] + ? [NK,space,v] = mffromlfun(L); NK + %4 = [4, 1, -4] + ? mf=mfinit(NK,space); w = mftobasis(mf,v) + %5 = [1.0000000000000000000000000000000000000]~ + ? [f] = mfbasis(mf); mfcoefs(f,10) \\ includes a_0 ! + %6 = [1/4, 1, 1, 0, 1, 2, 0, 0, 1, 1, 2] + @eprog + + If $L$ has inexact complex coefficients, one can for instance + compute an eigenbasis for \var{mf} and check whether one of the attached + $L$-function is reasonably close to $L$. In the example, we cheat by + producing the $L$ function from an eigenform in a known space, but the + function does not use this information: + \bprog + ? mf = mfinit([32,6,Mod(5,32)],0); + ? [poldegree(K) | K<-mffields(mf)] + %2 = [19] \\ one orbit, [Q(F) : Q(chi)] = 19 + ? L = lfunmf(mf)[1][1]; \\ one of the 19 L-functions attached to F + ? lfunan(L,3) + %4 = [1, 5.654... - 0.1812...*I, -7.876... - 19.02...*I] + ? [NK,space,v] = mffromlfun(L); NK + %5 = [32, 6, Mod(5, 32)] + ? vL = concat(lfunmf(mf)); \\ L functions for all cuspidal eigenforms + ? an = lfunan(L,10); + ? for (i = 1, #vL, if (normlp(lfunan(vL[i],10) - an, oo) < 1e-10, print(i))); + 1 + @eprog + +Function: mffromqf +Class: basic +Section: modular_forms +C-Name: mffromqf +Prototype: GDG +Help: mffromqf(Q,{P}): Q being an even positive definite quadratic form + and P a homogeneous spherical polynomial for Q, computes a 3-component vector + [mf,F,coeffs], where F is the theta function corresponding to (Q, P), mf is + the corresponding space of modular forms from mfinit, and coeffs are the + coefficients of F on mfbasis(mf). +Doc: $Q$ being an even integral positive definite quadratic form + and $P$ a homogeneous spherical polynomial for $Q$, computes + a 3-component vector $[\var{mf},F,v]$, where $F$ is the theta function + corresponding to $(Q,P)$, \var{mf} is the corresponding space of modular + forms (from \kbd{mfinit}), and $v$ gives the coefficients of $F$ on + \kbd{mfbasis(mf)}. + \bprog + ? [mf,F,v] = mffromqf(2*matid(10)); v + %1 = [64/5, 4/5, 32/5]~ + ? mfcoefs(F, 5) + %2 = [1, 20, 180, 960, 3380, 8424] + ? mfcoef(F, 10000) \\ number of ways of writing 10000 as sum of 10 squares + %3 = 128205250571893636 + ? mfcoefs(F, 10000); \\ fast ! + time = 220ms + ? [mf,F,v] = mffromqf([2,0;0,2],x^4-6*x^2*y^2+y^4); + ? mfcoefs(F,10) + %6 = [0, 4, -16, 0, 64, -56, 0, 0, -256, 324, 224] + ? mfcoef(F,100000) \\ instantaneous + %7 = 41304367104 + @eprog + Odd dimensions are supported, corresponding to forms of half-integral weight: + \bprog + ? [mf,F,v] = mffromqf(2*matid(3)); + ? mfisequal(F, mfpow(mfTheta(),3)) + %2 = 1 + ? mfcoefs(F, 32) \\ illustrate Legendre's 3-square theorem + %3 = [ 1, + 6, 12, 8, 6, 24, 24, 0, 12, + 30, 24, 24, 8, 24, 48, 0, 6, + 48, 36, 24,24, 48, 24, 0, 24, + 30, 72, 32, 0, 72, 48, 0, 12] + @eprog + +Function: mfgaloisprojrep +Class: basic +Section: modular_forms +C-Name: mfgaloisprojrep +Prototype: GGp +Help: mfgaloisprojrep(mf,F): mf being an mf output by mfinit in weight 1, + and F an eigenform, returns a polynomial defining the field fixed by the + kernel of the projective representation associated to F. +Doc: \var{mf} being an \kbd{mf} output by \kbd{mfinit} in weight $1$, + return a polynomial defining the field fixed by the kernel of the projective + Artin representation attached to \var{F} (by Deligne--Serre). + Currently only implemented for projective images $A_{4}$, $A_{5}$ and $S_{4}$. + The type $A_{5}$ requires the \kbd{nflistdata} package to be installed. + + \bprog + \\ A4 example + ? mf = mfinit([4*31,1,Mod(87,124)],0); + ? F = mfeigenbasis(mf)[1]; + ? mfgaloistype(mf,F) + %3 = -12 + ? pol = mfgaloisprojrep(mf,F) + %4 = x^12 + 68*x^10 + 4808*x^8 + ... + 4096 + ? G = galoisinit(pol); galoisidentify(G) + %5 = [12,3] \\A4 + ? pol4 = polredbest(galoisfixedfield(G,G.gen[3], 1)) + %6 = x^4 + 7*x^2 - 2*x + 14 + ? polgalois(pol4) + %7 = [12, 1, 1, "A4"] + ? factor(nfdisc(pol4)) + %8 = + [ 2 4] + + [31 2] + + \\ S4 example + ? mf = mfinit([4*37,1,Mod(105,148)],0); + ? F = mfeigenbasis(mf)[1]; + ? mfgaloistype(mf,F) + %11 = -24 + ? pol = mfgaloisprojrep(mf,F) + %12 = x^24 + 24*x^22 + 256*x^20 + ... + 255488256 + ? G = galoisinit(pol); galoisidentify(G) + %13 = [24, 12] \\S4 + ? pol4 = polredbest(galoisfixedfield(G,G.gen[3..4], 1)) + %14 = x^4 - x^3 + 5*x^2 - 7*x + 12 + ? polgalois(pol4) + %15 = [24, -1, 1, "S4"] + ? factor(nfdisc(pol4)) + %16 = + [ 2 2] + + [37 3] + @eprog + +Function: mfgaloistype +Class: basic +Section: modular_forms +C-Name: mfgaloistype +Prototype: GDG +Help: mfgaloistype(NK,{F}): NK being either [N,1,CHI] or an mf + output by mfinit in weight 1 , gives the vector of + types of Galois representations attached to each cuspidal eigenform, + unless the eigenform F is specified, in which case only for F. + Types A_4, S_4, A_5 are represented by minus their cardinality -12, -24, + or -60, and type D_n is represented by its cardinality, the integer 2*n. +Doc: \kbd{NK} being either \kbd{[N,1,CHI]} or an \kbd{mf} output by + \kbd{mfinit} in weight $1$, gives the vector of types of Galois + representations attached to each cuspidal eigenform, + unless the modular form \kbd{F} is specified, in which case only for \kbd{F} + (note that it is not tested whether \kbd{F} belongs to the correct modular + form space, nor whether it is a cuspidal eigenform). Types $A_{4}$, $S_{4}$, + $A_{5}$ are represented by minus their cardinality $-12$, $-24$, or $-60$, + and type $D_{n}$ is represented by its cardinality, the integer $2n$: + \bprog + ? mfgaloistype([124,1, Mod(67,124)]) \\ A4 + %1 = [-12] + ? mfgaloistype([148,1, Mod(105,148)]) \\ S4 + %2 = [-24] + ? mfgaloistype([633,1, Mod(71,633)]) \\ D10, A5 + %3 = [10, -60] + ? mfgaloistype([239,1, -239]) \\ D6, D10, D30 + %4 = [6, 10, 30] + ? mfgaloistype([71,1, -71]) + %5 = [14] + ? mf = mfinit([239,1, -239],0); F = mfeigenbasis(mf)[2]; + ? mfgaloistype(mf, F) + %7 = 10 + @eprog + The function may also return~$0$ as a type when it failed to determine it; in + this case the correct type is either~$-12$ or~$-60$, and most likely~$-12$. + +Function: mfhecke +Class: basic +Section: modular_forms +C-Name: mfhecke +Prototype: GGL +Help: mfhecke(mf,F,n): F being a modular form in space mf, returns T(n)F, + where T(n) is the n-th Hecke operator. Warning: if F is of level M= 3/2, gives a basis B of the Kohnen + space of mf as a matrix + whose columns are the coefficients of B on the basis of mf. +Doc: \kbd{mf} being a cuspidal space of half-integral weight $k\ge3/2$ + with level $N$ and character $\chi$, gives a + basis $B$ of the Kohnen $+$-space of \kbd{mf} as a matrix whose columns are + the coefficients of $B$ on the basis of \kbd{mf}. The conductor of either + $\chi$ or $\chi \cdot (-4/.)$ must divide $N/4$. + \bprog + ? mf = mfinit([36,5/2],1); K = mfkohnenbasis(mf); K~ + %1 = + [-1 0 0 2 0 0] + + [ 0 0 0 0 1 0] + ? (mfcoefs(mf,20) * K)~ + %4 = + [0 -1 0 0 2 0 0 0 0 0 0 0 0 -6 0 0 8 0 0 0 0] + + [0 0 0 0 0 1 0 0 -2 0 0 0 0 0 0 0 0 1 0 0 2] + + ? mf = mfinit([40,3/2,8],1); mfkohnenbasis(mf) + *** at top-level: mfkohnenbasis(mf) + *** ^----------------- + *** mfkohnenbasis: incorrect type in mfkohnenbasis [incorrect CHI] (t_VEC). + @eprog In the final example both $\chi = (8/.)$ and $\chi \cdot (-4/.)$ + have conductor $8$, which does not divide N/4 = 10. + +Function: mfkohnenbijection +Class: basic +Section: modular_forms +C-Name: mfkohnenbijection +Prototype: G +Help: mfkohnenbijection(mf): mf being a cuspidal space of half-integral weight + returns [mf2,M,K,shi], where M is a matrix giving a Hecke-module + isomorphism from S_{2k-1}(N,CHI^2) given by mf2 to the Kohnen + space + S_k+(4N,CHI), K is a basis of the Kohnen + space, and shi gives + the linear combination of Shimura lifts giving M^(-1). +Doc: Let \kbd{mf} be a cuspidal space of half-integral weight and weight $4N$, + with $N$ squarefree and let $S_{k}^{+}(\Gamma_{0}(4N),\chi)$ be the Kohnen + $+$-space. Returns \kbd{[mf2,M,K,shi]}, where + + \item \kbd{mf2} gives the cuspidal space $S_{2k-1}(\Gamma_{0}(N),\chi^{2})$; + + \item $M$ is a matrix giving a Hecke-module isomorphism from that space to the + Kohnen $+$-space $S_{k}^{+}(\Gamma_{0}(4N),\chi)$; + + \item \kbd{K} represents a basis $B$ of the Kohnen $+$-space as a matrix + whose columns are the coefficients of $B$ on the basis of \kbd{mf}; + + \item \kbd{shi} is a vector of pairs $(t_{i},n_{i})$ gives the linear + combination of Shimura lifts giving $M^{-1}$: $t_{i}$ is a squarefree positive + integer and $n_{i}$ is a small nonzero integer. + + \bprog + ? mf=mfinit([60,5/2],1); [mf2,M,K,shi]=mfkohnenbijection(mf); M + %2 = + [-3 0 5/2 7/2] + + [ 1 -1/2 -7 -7] + + [ 1 1/2 0 -3] + + [ 0 0 5/2 5/2] + + ? shi + %2 = [[1, 1], [2, 1]] + @eprog + This last command shows that the map giving the bijection is the sum of the + Shimura lift with $t=1$ and the one with $t=2$. + + Since it gives a bijection of Hecke modules, this matrix can be used to + transport modular form data from the easily computed space of level $N$ + and weight $2k-1$ to the more difficult space of level $4N$ and weight + $k$: matrices of Hecke operators, new space, splitting into eigenspaces and + eigenforms. Examples: + \bprog + ? K^(-1)*mfheckemat(mf,121)*K /* matrix of T_11^2 on K. Slowish. */ + time = 1,280 ms. + %1 = + [ 48 24 24 24] + + [ 0 32 0 -20] + + [-48 -72 -40 -72] + + [ 0 0 0 52] + ? M*mfheckemat(mf2,11)*M^(-1) /* instantaneous via T_11 on S_{2k-1} */ + time = 0 ms. + %2 = + [ 48 24 24 24] + + [ 0 32 0 -20] + + [-48 -72 -40 -72] + + [ 0 0 0 52] + ? mf20=mfinit(mf2,0); [mftobasis(mf2,b) | b<-mfbasis(mf20)] + %3 = [[0, 0, 1, 0]~, [0, 0, 0, 1]~] + ? F1=M*[0,0,1,0]~ + %4 = [1/2, 1/2, -3/2, -1/2]~ + ? F2=M*[0,0,0,1]~ + %5 = [3/2, 1/2, -9/2, -1/2] + ? K*F1 + %6 = [1, 0, 0, 1, 1, 0, 0, 1, -3, 0, 0, -3, 0, 0]~ + ? K*F2 + %7 = [3, 0, 0, 3, 1, 0, 0, 1, -9, 0, 0, -3, 0, 0]~ + @eprog + + This gives a basis of the new space of $S_{5/2}^{+}(\Gamma_{0}(60))$ expressed + on the initial basis of $S_{5/2}(\Gamma_{0}(60))$. To obtain the eigenforms, + we write instead: + \bprog + ? BE=mfeigenbasis(mf20);[E1,E2]=apply(x->K*M*mftobasis(mf2,x),BE) + %1 = [[1, 0, 0, 1, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0]~,\ + [0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, -3, 0, 0]~ + ? EI1 = mflinear(mf, E1); EI2=mflinear(mf, E2); + @eprog\noindent + These are the two eigenfunctions in the space \kbd{mf}, the first (resp., + second) will have Shimura image a multiple of $BE[1]$ (resp., $BE[2]$). + The function \kbd{mfkohneneigenbasis} does this directly. + +Function: mfkohneneigenbasis +Class: basic +Section: modular_forms +C-Name: mfkohneneigenbasis +Prototype: GG +Help: mfkohneneigenbasis(mf,bij): mf being a cuspidal space of half-integral + weight k >= 3/2 and bij being the output of mfkohnenbijection(mf), outputs + a 3-component vector [mf0,BNEW,BEIGEN], where BNEW and BEIGEN are two + matrices whose columns are the coefficients of a basis of the Kohnen new + space and of the eigenforms on the basis of mf respectively, and mf0 is + the corresponding new space of integral weight 2k - 1. +Doc: \kbd{mf} being a cuspidal space of half-integral weight $k\ge3/2$ and + \kbd{bij} being the output of \kbd{mfkohnenbijection(mf)}, outputs a + $3$-component vector \kbd{[mf0,BNEW,BEIGEN]}, where \kbd{BNEW} and + \kbd{BEIGEN} are two matrices whose columns are the coefficients + of a basis of the Kohnen new space and of the eigenforms on the basis of + \kbd{mf} respectively, and \kbd{mf0} is the corresponding new space of + integral weight $2k-1$. + \bprog + ? mf=mfinit([44,5/2],1);bij=mfkohnenbijection(mf); + ? [mf0,BN,BE]=mfkohneneigenbasis(mf,bij); + ? BN~ + %2 = + [2 0 0 -2 2 0 -8] + + [2 0 0 4 14 0 -32] + + ? BE~ + %3 = [1 0 0 Mod(y-1, y^2-3) Mod(2*y+1, y^2-3) 0 Mod(-4*y-4, y^2-3)] + ? lift(mfcoefs(mf,20)*BE[,1]) + %4 = [0, 1, 0, 0, y - 1, 2*y + 1, 0, 0, 0, -4*y - 4, 0, 0,\ + -5*y + 3, 0, 0, 0, -6, 0, 0, 0, 7*y + 9]~ + @eprog + +Function: mflinear +Class: basic +Section: modular_forms +C-Name: mflinear +Prototype: GG +Help: mflinear(vF,v): vF being a vector of modular forms and v + a vector of coefficients of same length, compute the linear + combination of the entries of vF with coefficients v. +Doc: \kbd{vF} being a vector of generalized modular forms and \kbd{v} + a vector of coefficients of same length, compute the linear + combination of the entries of \kbd{vF} with coefficients \kbd{v}. + \misctitle{Note} Use this in particular to subtract two forms $F$ and $G$ + (with $vF=[F,G]$ and $v=[1,-1]$), or to multiply an form by + a scalar $\lambda$ (with $vF=[F]$ and $v=[\lambda]$). + \bprog + ? D = mfDelta(); G = mflinear([D],[-3]); + ? mfcoefs(G,4) + %2 = [0, -3, 72, -756, 4416] + @eprog For user convenience, we allow + + \item a modular form space \kbd{mf} as a \kbd{vF} argument, which is + understood as \kbd{mfbasis(mf)}; + + \item in this case, we also allow a modular form $f$ as $v$, which + is understood as \kbd{mftobasis}$(\var{mf}, f)$. + + \bprog + ? T = mfpow(mfTheta(),7); F = mfShimura(T,-3); \\ Shimura lift for D=-3 + ? mfcoefs(F,8) + %2 = [-5/9, 280, 9240, 68320, 295960, 875280, 2254560, 4706240, 9471000] + ? mf = mfinit(F); G = mflinear(mf,F); + ? mfcoefs(G,8) + %4 = [-5/9, 280, 9240, 68320, 295960, 875280, 2254560, 4706240, 9471000] + @eprog\noindent This last construction allows to replace a general modular + form by a simpler linear combination of basis functions, which is often + more efficient: + \bprog + ? T10=mfpow(mfTheta(),10); mfcoef(T10, 10^4) \\ direct evaluation + time = 399 ms. + %5 = 128205250571893636 + ? mf=mfinit(T10); F=mflinear(mf,T10); \\ instantaneous + ? mfcoef(F, 10^4) \\ after linearization + time = 67 ms. + %7 = 128205250571893636 + @eprog + +Function: mfmanin +Class: basic +Section: modular_forms +C-Name: mfmanin +Prototype: Gb +Help: mfmanin(FS): Given the modular symbol FS associated to an eigenform F + by mfsymbol(mf,F), computes the even and odd special polynomials as well as + the even and odd periods om+ and om- as a vector [[P+,P-],[om+,om-,r]], + where r = imag(om+*conj(om-))/. + If F has several embeddings into C, give the vector of results corresponding + to each embedding. +Doc: Given the modular symbol $FS$ associated to an eigenform $F$ by + \kbd{mfsymbol(mf,F)}, computes the even and odd special polynomials as well + as the even and odd periods $\omega^{+}$ and $\omega^{-}$ as a vector + $[[P^{+},P^{-}],[\omega^{+},\omega^{-},r]]$, where + $r=\Im(\omega^{+}\overline{\omega^{-}})/$. If $F$ has several embeddings + into $\C$, give the vector of results corresponding to each embedding. + \bprog + ? D=mfDelta(); mf=mfinit(D); DS=mfsymbol(mf,D); + ? [pols,oms]=mfmanin(DS); pols + %2 = [[4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x],\ + [-36*x^10 + 691*x^8 - 2073*x^6 + 2073*x^4 - 691*x^2 + 36]] + ? oms + %3 = [0.018538552324740326472516069364750571812,\ + -0.00033105361053212432521308691198949874026*I, 4096/691] + ? mf=mfinit([11,2],0); F=mfeigenbasis(mf)[1]; FS=mfsymbol(mf,F); + ? [pols,oms]=mfmanin(FS);pols + %5 = [[0, 0, 0, 1, 1, 0, 0, -1, -1, 0, 0, 0],\ + [2, 0, 10, 5, -5, -10, -10, -5, 5, 10, 0, -2]] + ? oms[3] + %6 = 24/5 + @eprog + +Function: mfmul +Class: basic +Section: modular_forms +C-Name: mfmul +Prototype: GG +Help: mfmul(F,G): Multiply the two forms F and G. +Doc: Multiply the two generalized modular forms $F$ and $G$. + \bprog + ? E4 = mfEk(4); G = mfmul(mfmul(E4,E4),E4); + ? mfcoefs(G, 4) + %2 = [1, 720, 179280, 16954560, 396974160] + ? mfcoefs(mfpow(E4,3), 4) + %3 = [1, 720, 179280, 16954560, 396974160] + @eprog + +Function: mfnumcusps +Class: basic +Section: modular_forms +C-Name: mfnumcusps +Prototype: G +Help: mfnumcusps(N): number of cusps of Gamma_0(N) +Doc: number of cusps of $\Gamma_{0}(N)$ + \bprog + ? mfnumcusps(24) + %1 = 8 + ? mfcusps(24) + %1 = [0, 1/2, 1/3, 1/4, 1/6, 1/8, 1/12, 1/24] + @eprog + +Function: mfparams +Class: basic +Section: modular_forms +C-Name: mfparams +Prototype: G +Help: mfparams(F): If F is a modular form space, returns [N,k,CHI,space,Phi]: + level, weight, character, and space code; where Phi is the cyclotomic + polynomial defining the field of values of CHI. If F is a modular form, + returns [N,k,CHI,P,Phi], where P is the (polynomial giving the) field of + definition of F: in that case the level N may be a multiple of the level of F + and the polynomial P may define a larger field than Q(F). +Doc: If $F$ is a modular form space, returns \kbd{[N,k,CHI,space,$\Phi$]}, + level, weight, character $\chi$, and space code; where $\Phi$ is the + cyclotomic polynomial + defining the field of values of \kbd{CHI}. If $F$ is a generalized modular + form, returns \kbd{[N,k,CHI,P,$\Phi$]}, where $P$ is the (polynomial giving + the) field of definition of $F$ as a relative extension of the cyclotomic field + $\Q(\chi) = \Q[t]/(\Phi)$: in that case the level $N$ may be a multiple of the + level of $F$ and the polynomial $P$ may define a larger field than $\Q(F)$. + If you want the true level of $F$ from this result, use + \kbd{mfconductor(mfinit(F),F)}. The polynomial $P$ defines an extension of + $\Q(\chi) = \Q[t]/(\Phi(t))$; it has coefficients in that number field + (polmods in $t$). + + In contrast with \kbd{mfparams(F)[4]} which always gives the polynomial + $P$ defining the relative extension $\Q(F)/\Q(\chi)$, the member function + \kbd{$F$.mod} returns the polynomial used to define $\Q(F)$ over $\Q$ + (either a cyclotomic polynomial or a polynomial with cyclotomic + coefficients). + + \bprog + ? E1 = mfeisenstein(4,-3,-4); E2 = mfeisenstein(3,5,-7); E3 = mfmul(E1,E2); + ? apply(mfparams, [E1,E2,E3]) + %2 = [[12, 4, 12, y, t-1], [35, 3, -35, y, t-1], [420, 7, -420, y, t-1]] + + ? mf = mfinit([36,2,Mod(13,36)],0); [f] = mfeigenbasis(mf); mfparams(mf) + %3 = [36, 2, Mod(13, 36), 0, t^2 + t + 1] + ? mfparams(f) + %4 = [36, 2, Mod(13, 36), y, t^2 + t + 1] + ? f.mod + %5 = t^2 + t + 1 + + ? mf = mfinit([36,4,Mod(13,36)],0); [f] = mfeigenbasis(mf); + ? lift(mfparams(f)) + %7 = [36, 4, 13, y^3 + (2*t-2)*y^2 + (-4*t+6)*y + (10*t-1), t^2+t+1] + @eprog + +Function: mfperiodpol +Class: basic +Section: modular_forms +C-Name: mfperiodpol +Prototype: GGD0,L,b +Help: mfperiodpol(mf,f,{flag=0}): period polynomial of the cuspidal part of + the form f, in other words integral from 0 to ioo of (X-tau)^(k-2)f(tau). + If flag=0, ordinary period polynomial, if flag=1 or -1, even or odd + part of that polynomial. f can also be the modular symbol output by + mfsymbol(mf,f). +Doc: period polynomial of the cuspidal part of the form $f$, in other words + $\int_{0}^{i\infty}(X-\tau)^{k-2}f(\tau)\,d\tau$. If $\fl=0$, + ordinary period polynomial. If it is $1$ or $-1$, even or odd part of that + polynomial. $f$ can also be the modular symbol output by \kbd{mfsymbol}(mf,f). + \bprog + ? D = mfDelta(); mf = mfinit(D,0); + ? PP = mfperiodpol(mf, D, -1); PP/=polcoef(PP, 1); bestappr(PP) + %1 = x^9 - 25/4*x^7 + 21/2*x^5 - 25/4*x^3 + x + ? PM = mfperiodpol(mf, D, 1); PM/=polcoef(PM, 0); bestappr(PM) + %2 = -x^10 + 691/36*x^8 - 691/12*x^6 + 691/12*x^4 - 691/36*x^2 + 1 + @eprog + +Function: mfperiodpolbasis +Class: basic +Section: modular_forms +C-Name: mfperiodpolbasis +Prototype: LD0,L, +Help: mfperiodpolbasis(k,{flag=0}): basis of period polynomials for weight k. + If flag=1 or -1, basis of odd or even period polynomials. +Doc: Basis of period polynomials for weight $k$. If $\fl=1$ or $-1$, basis of + odd or even period polynomials. + \bprog + ? mfperiodpolbasis(12,1) + %1 = [x^8 - 3*x^6 + 3*x^4 - x^2, x^10 - 1] + ? mfperiodpolbasis(12,-1) + %2 = [4*x^9 - 25*x^7 + 42*x^5 - 25*x^3 + 4*x] + @eprog + +Function: mfpetersson +Class: basic +Section: modular_forms +C-Name: mfpetersson +Prototype: GDG +Help: mfpetersson(fs,{gs}): Petersson scalar product of the modular + forms f and g belonging to the same modular form space mf, given by + the corresponding "modular symbols" fs and gs output by mfsymbol + (also in weight 1 and half-integral weight). If gs is omitted + it is understood to be equal to fs. The scalar product is normalized by the + factor 1/[G:G_0(N)]. +Doc: Petersson scalar product of the modular forms $f$ and $g$ belonging to + the same modular form space \kbd{mf}, given by the corresponding + ``modular symbols'' \kbd{fs} and \kbd{gs} output by \kbd{mfsymbol} + (also in weight $1$ and half-integral weight, where symbols do not exist). + If \kbd{gs} is omitted it is understood to be equal to \kbd{fs}. + The scalar product is normalized by the factor $1/[\Gamma:\Gamma_{0}(N)]$. + Note that $f$ and $g$ can both be noncuspidal, in which case the program + returns an error if the product is divergent. + If the fields of definition $\Q(f)$ and $\Q(g)$ are equal to $\Q(\chi)$ + the result is a scalar. If $[\Q(f):\Q(\chi)]=d>1$ and + $[\Q(g):\Q(\chi)]=e>1$ the result is a $d\times e$ matrix corresponding + to all the embeddings of $f$ and $g$. In the intermediate cases $d=1$ or + $e=1$ the result is a row or column vector. + \bprog + ? D=mfDelta(); mf=mfinit(D); DS=mfsymbol(mf,D); mfpetersson(DS) + %1 = 1.0353620568043209223478168122251645932 E-6 + ? mf=mfinit([11,6],0);B=mfeigenbasis(mf);BS=vector(#B,i,mfsymbol(mf,B[i])); + ? mfpetersson(BS[1]) + %3 = 1.6190120685220988139111708455305245466 E-5 + ? mfpetersson(BS[1],BS[2]) + %4 = [-3.826479006582967148 E-42 - 2.801547395385577002 E-41*I,\ + 1.6661127341163336125 E-41 + 1.1734725972345985061 E-41*I,\ + 0.E-42 - 6.352626992842664490 E-41*I]~ + ? mfpetersson(BS[2]) + %5 = + [ 2.7576133733... E-5 2.0... E-42 6.3... E-43 ] + + [ -4.1... E-42 6.77837030070... E-5 3.3...E-42 ] + + [ -6.32...E-43 3.6... E-42 2.27268958069... E-5] + + ? mf=mfinit([23,2],0); F=mfeigenbasis(mf)[1]; FS=mfsymbol(mf,F); + ? mfpetersson(FS) + %5 = + [0.0039488965740025031688548076498662860143 -3.56 ... E-40] + + [ -3.5... E-40 0.0056442542987647835101583821368582485396] + @eprog + + Noncuspidal example: + \bprog + ? E1=mfeisenstein(5,1,-3);E2=mfeisenstein(5,-3,1); + ? mf=mfinit([12,5,-3]); cusps=mfcusps(12); + ? apply(x->mfcuspval(mf,E1,x),cusps) + %3 = [0, 0, 1, 0, 1, 1] + ? apply(x->mfcuspval(mf,E2,x),cusps) + %4 = [1/3, 1/3, 0, 1/3, 0, 0] + ? E1S=mfsymbol(mf,E1);E2S=mfsymbol(mf,E2); + ? mfpetersson(E1S,E2S) + %6 = -1.884821671646... E-5 - 1.9... E-43*I + @eprog + + Weight 1 and 1/2-integral weight example: + \bprog + ? mf=mfinit([23,1,-23],1);F=mfbasis(mf)[1];FS=mfsymbol(mf,F); + ? mfpetersson(mf,FS) + %2 = 0.035149946790370230814006345508484787443 + ? mf=mfinit([4,9/2],1);F=mfbasis(mf)[1];FS=mfsymbol(mf,F); + ? mfpetersson(FS) + %4 = 0.00015577084407139192774373662467908966030 + @eprog + +Function: mfpow +Class: basic +Section: modular_forms +C-Name: mfpow +Prototype: GL +Help: mfpow(F,n): compute F^n +Doc: Compute $F^{n}$, where $n$ is an integer and $F$ is a generalized modular + form: + \bprog + ? G = mfpow(mfEk(4), 3); \\ E4^3 + ? mfcoefs(G, 4) + %2 = [1, 720, 179280, 16954560, 396974160] + @eprog + +Function: mfsearch +Class: basic +Section: modular_forms +C-Name: mfsearch +Prototype: GGD4,L, +Help: mfsearch(NK,V,{space}): NK being of the form [N,k] with k possibly + half-integral, search for a modular form with rational coefficients, of weight + k and level N, whose initial coefficients a(0),... are equal to V; space + specifies the modular form spaces in which to search. The output is a list + of matching forms with that given level and weight. Note that the character + is of the form (D/.), where D is a (positive or negative) fundamental + discriminant dividing N. + + N can be replaced by a vector of allowed levels, in which case the list of + forms is sorted by increasing level, then increasing |D|. If a form is found + at level N, any multiple of N with the same D is not considered + + Note that this is very different from mfeigensearch, which only searches for + rational eigenforms. +Doc: \kbd{NK} being of the form \kbd{[N,k]} with $k$ possibly half-integral, + search for a modular form with rational coefficients, of weight $k$ and + level $N$, whose initial coefficients $a(0)$,... are equal to $V$; + \kbd{space} specifies the modular form spaces in which to search, in + \kbd{mfinit} or \kbd{mfdim} notation. The output is a list of matching forms + with that given level and weight. Note that the character is of the form + $(D/.)$, where $D$ is a (positive or negative) fundamental discriminant + dividing $N$. The forms are sorted by increasing $|D|$. + + The parameter $N$ can be replaced by a vector of allowed levels, in which + case the list of forms is sorted by increasing level, then increasing $|D|$. + If a form is found at level $N$, any multiple of $N$ with the same $D$ is not + considered. Some useful possibilities are + + \item \kbd{[$N_{1}$..$N_{2}$]}: all levels between $N_{1}$ and $N_{2}$, + endpoints included; + + \item \kbd{$F$ * [$N_{1}$..$N_{2}$]}: same but levels divisible by $F$; + + \item \kbd{divisors}$(N_{0})$: all levels dividing $N_{0}$. + + Note that this is different from \kbd{mfeigensearch}, which only searches + for rational eigenforms. + + \bprog + ? F = mfsearch([[1..40], 2], [0,1,2,3,4], 1); #F + %1 = 3 + ? [ mfparams(f)[1..3] | f <- F ] + %2 = [[38, 2, 1], [40, 2, 8], [40, 2, 40]] + ? mfcoefs(F[1],10) + %3 = [0, 1, 2, 3, 4, -5, -8, 1, -7, -5, 7] + @eprog + +Function: mfshift +Class: basic +Section: modular_forms +C-Name: mfshift +Prototype: GL +Help: mfshift(F,s): Divide the form F by q^s omitting the remainder if there + is one; s can be negative. +Doc: Divide the generalized modular form $F$ by $q^{s}$, omitting the remainder + if there is one. One can have $s<0$. + \bprog + ? D=mfDelta(); mfcoefs(mfshift(D,1), 4) + %1 = [1, -24, 252, -1472, 4830] + ? mfcoefs(mfshift(D,2), 4) + %2 = [-24, 252, -1472, 4830, -6048] + ? mfcoefs(mfshift(D,-1), 4) + %3 = [0, 0, 1, -24, 252] + @eprog + +Function: mfshimura +Class: basic +Section: modular_forms +C-Name: mfshimura +Prototype: GGD1,L, +Help: mfshimura(mf,F,{D=1}): F being a modular form of + half-integral weight k >= 3/2 and D a positive squarefree integer, + computes the Shimura lift G of weight 2k-1 corresponding to D. This function + returns [mf2,G,v], where mf2 is a modular form space containing G, and v the + vector of coefficients of G on mf. +Doc: $F$ being a modular form of half-integral weight $k\geq 3/2$ and $D$ a + positive squarefree integer, returns the Shimura lift $G$ of weight $2k-1$ + corresponding to $D$. This function returns $[\var{mf2},G,v]$ + where \var{mf2} is a modular form space containing $G$ and $v$ expresses $G$ + in terms of \kbd{mfbasis}$(\var{mf2})$; so that $G$ is + \kbd{mflinear}$(\var{mf2},v)$. + \bprog + ? F = mfpow(mfTheta(), 7); mf = mfinit(F); + ? [mf2, G, v] = mfshimura(mf, F, 3); mfcoefs(G,5) + %2 = [-5/9, 280, 9240, 68320, 295960, 875280] + ? mfparams(G) \\ the level may be lower than expected + %3 = [1, 6, 1, y, t - 1] + ? mfparams(mf2) + %4 = [2, 6, 1, 4, t - 1] + ? v + %5 = [280, 0]~ + ? mfcoefs(mf2, 5) + %6 = + [-1/504 -1/504] + + [ 1 0] + + [ 33 1] + + [ 244 0] + + [ 1057 33] + + [ 3126 0] + ? mf = mfinit([60,5/2],1); F = mflinear(mf,mfkohnenbasis(mf)[,1]); + ? mfparams(mfshimura(mf,F)[2]) + %8 = [15, 4, 1, y, t - 1] + ? mfparams(mfshimura(mf,F,6)[2]) + %9 = [15, 4, 1, y, t - 1] + @eprog + +Function: mfslashexpansion +Class: basic +Section: modular_forms +C-Name: mfslashexpansion +Prototype: GGGLLD&p +Help: mfslashexpansion(mf,f,g,n,flrat,{¶ms}): g being in M_2^+(Q), + computes the Fourier expansion of f|_k g to n terms. f must belong to + the space mf. If params is given, it is set to the parameters [alpha,w,A]. + If flrat is 1, the program tries to rationalize the expression; if flag + is 0, it does not. +Doc: let \var{mf} be a modular form space in level $N$, $f$ a modular form + belonging to \var{mf} and let $g$ be in $M_{2}^{+}(Q)$. This function + computes the Fourier expansion of $f|_{k} g$ to $n$ terms. We first describe + the behaviour when \kbd{flrat} is 0: the result is a + vector $v$ of floating point complex numbers such that + $$f|_{k} g(\tau) = q^{\alpha} \sum_{m\ge0} v[m+1] q^{m/w},$$ + where $q = e(\tau)$, $w$ is the width of the cusp $g(i\infty)$ + (namely $(N/(c^{2},N)$ if $g$ is integral) and $\alpha$ is a rational number. + If \kbd{params} is given, it is set to the parameters $[\alpha,w, + \kbd{matid}(2)]$. + + If \kbd{flrat} is 1, the program tries to rationalize the expression, i.e., + to express the coefficients as rational numbers or polmods. We + write $g = \lambda \cdot M \cdot A$ where $\lambda \in \Q^{*}$, + $M\in \text{SL}_{2}(\Z)$ and $A = [a,b;0,d]$ is upper triangular, + integral and primitive with $a > 0$, $d > 0$ and $0 \leq b < d$. Let + $\alpha$ and $w$ by the parameters attached to the expansion of + $F := f |_{k} M$ as above, i.e. + $$ F(\tau) = q^{\alpha} \sum_{m\ge0} v[m+1] q^{m/w}.$$ + The function returns the expansion $v$ of $F = f |_{k} M$ and sets + the parameters to $[\alpha, w, A]$. Finally, the desired expansion is + $(a/d)^{k/2} F(\tau + b/d)$. The latter is identical to the returned + expansion when $A$ is the identity, i.e. when $g\in \text{PSL}_{2}(\Z)$. + If this is not the case, the expansion differs from $v$ by the multiplicative + constant $(a/d)^{k/2} e(\alpha b/(dw))$ and a twist by a root of unity + $q^{1/w} \to e(b/(dw)) q^{1/w}$. The complications introduced by this extra + matrix $A$ allow to recognize the coefficients in a much smaller cyclotomic + field, hence to obtain a simpler description overall. (Note that this + rationalization step may result in an error if the program cannot perform it.) + + \bprog + ? mf = mfinit([32,4],0); f = mfbasis(mf)[1]; + ? mfcoefs(f, 10) + %2 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 47, 0] + ? mfatk = mfatkininit(mf,32); mfcoefs(mfatkin(mfatk,f),10) / mfatk[3] + %3 = [0, 1, 0, 16, 0, 22, 0, 32, 0, -27, 0] + ? mfatk[3] \\ here normalizing constant C = 1, but need in general + %4 = 1 + ? mfslashexpansion(mf,f,[0,-1;1,0],10,1,¶ms) * 32^(4/2) + %5 = [0, 1, 0, 16, 0, 22, 0, 32, 0, -27, 0] + ? params + %6 = [0, 32, [1, 0; 0, 1]] + + ? mf = mfinit([12,8],0); f = mfbasis(mf)[1]; + ? mfslashexpansion(mf,f,[1,0;2,1],7,0) + %7 = [0, 0, 0, 0.6666666... + 0.E-38*I, 0, -3.999999... + 6.92820...*I, 0,\ + -11.99999999... - 20.78460969...*I] + ? mfslashexpansion(mf,f,[1,0;2,1],7,1, ¶ms) + %8 = [0, 0, 0, 2/3, 0, Mod(8*t, t^2+t+1), 0, Mod(-24*t-24, t^2+t+1)] + ? params + %9 = [0, 3, [1, 0; 0, 1]] + @eprog + If $[\Q(f):\Q(\chi)]>1$, the coefficients may be polynomials in $y$, + where $y$ is any root of the polynomial giving the field of definition of + $f$ (\kbd{f.mod} or \kbd{mfparams(f)[4]}). + \bprog + ? mf=mfinit([23,2],0);f=mfeigenbasis(mf)[1]; + ? mfcoefs(f,5) + %1 = [Mod(0, y^2 - y - 1), Mod(1, y^2 - y - 1), Mod(-y, y^2 - y - 1),\ + Mod(2*y - 1, y^2 - y - 1), Mod(y - 1, y^2 - y - 1), Mod(-2*y, y^2 - y - 1)] + ? mfslashexpansion(mf,f,[1,0;0,1],5,1) + %2 = [0, 1, -y, 2*y - 1, y - 1, -2*y] + ? mfslashexpansion(mf,f,[0,-1;1,0],5,1) + %3 = [0, -1/23, 1/23*y, -2/23*y + 1/23, -1/23*y + 1/23, 2/23*y] + @eprog + \misctitle{Caveat} In half-integral weight, we \emph{define} the ``slash'' + operation as + $$(f |_{k} g)(\tau) := \big((c \tau + d)^{-1/2}\big)^{2k} f( g\cdot \tau),$$ + with the principal determination of the square root. In particular, + the standard cocycle condition is no longer satisfied and we only + have $f | (gg') = \pm (f | g) | g'$. + +Function: mfspace +Class: basic +Section: modular_forms +C-Name: mfspace +Prototype: lGDG +Help: mfspace(mf,{f}): identify the modular space mf, resp. the modular form f + in mf. Returns 0 (newspace), 1 (cuspidal space), 2 (old space), + 3 (Eisenstein space) or 4 (full space). Return -1 when the form does not + belong to the space. +Doc: identify the modular space \var{mf}, resp.~the modular form $f$ in + \var{mf} if present, as the flag given to \kbd{mfinit}. + Returns 0 (newspace), 1 (cuspidal space), 2 (old space), + 3 (Eisenstein space) or 4 (full space). + \bprog + ? mf = mfinit([1,12],1); mfspace(mf) + %1 = 1 + ? mfspace(mf, mfDelta()) + %2 = 0 \\ new space + @eprog\noindent This function returns $-1$ when the form $f$ is modular + but does not belong to the space. + \bprog + ? mf = mfinit([1,2]; mfspace(mf, mfEk(2)) + %3 = -1 + @eprog When $f$ is not modular and is for instance only quasi-modular, the + function returns nonsense: + \bprog + ? M6 = mfinit([1,6]); + ? dE4 = mfderiv(mfEk(4)); \\ not modular ! + ? mfspace(M6,dE4) \\ asserts (wrongly) that E4' belongs to new space + %3 = 0 + @eprog + +Function: mfsplit +Class: basic +Section: modular_forms +C-Name: mfsplit +Prototype: GD0,L,D0,L, +Help: mfsplit(mf,{dimlim=0},{flag=0}): mf containing the new space + split the new space into Galois + orbits of eigenforms of the newspace and return [vF,vK], where vF gives + the (Galois orbit of) eigenforms in terms of mfbasis(mf) and vK is a list of + polynomials defining each Galois orbit. If dimlim is set only the Galois + orbits of dimension <= dimlim are computed (i.e. the rational eigenforms if + dimlim = 1 and the character is real). Flag speeds up computations when the + dimension is large: if flag = d > 0, when the dimension of the eigenspace + is > d, only the Galois polynomial is computed. +Doc: \kbd{mf} from \kbd{mfinit} with integral weight containing the new space + (either the new space itself or the cuspidal space or the full space), and + preferably the newspace itself for efficiency, split the space into Galois + orbits of eigenforms of the newspace, satisfying various restrictions. + + The functions returns $[vF, vK]$, where $vF$ gives (Galois orbit of) + eigenforms and $vK$ is a list of polynomials defining each Galois orbit. + The eigenforms are given in \kbd{mftobasis} format, i.e. as a matrix + whose columns give the forms with respect to \kbd{mfbasis(mf)}. + + If \kbd{dimlim} is set, only the Galois orbits of dimension $\leq \kbd{dimlim}$ + are computed (i.e. the rational eigenforms if $\kbd{dimlim} = 1$ and the + character is real). This can considerably speed up the function when a Galois + orbit is defined over a large field. + + $\fl$ speeds up computations when the dimension is large: if $\fl=d>0$, + when the dimension of the eigenspace is $>d$, only the Galois polynomial is + computed. + + Note that the function \kbd{mfeigenbasis} returns all eigenforms in an + easier to use format (as modular forms which can be input as is in other + functions); \kbd{mfsplit} is only useful when you can restrict + to orbits of small dimensions, e.g. rational eigenforms. + + \bprog + ? mf=mfinit([11,2],0); f=mfeigenbasis(mf)[1]; mfcoefs(f,16) + %1 = [0, 1, -2, -1, ...] + ? mf=mfinit([23,2],0); f=mfeigenbasis(mf)[1]; mfcoefs(f,16) + %2 = [Mod(0, z^2 - z - 1), Mod(1, z^2 - z - 1), Mod(-z, z^2 - z - 1), ...] + ? mf=mfinit([179,2],0); apply(poldegree, mffields(mf)) + %3 = [1, 3, 11] + ? mf=mfinit([719,2],0); + ? [vF,vK] = mfsplit(mf, 5); \\ fast when restricting to small orbits + time = 192 ms. + ? #vF \\ a single orbit + %5 = 1 + ? poldegree(vK[1]) \\ of dimension 5 + %6 = 5 + ? [vF,vK] = mfsplit(mf); \\ general case is slow + time = 2,104 ms. + ? apply(poldegree,vK) + %8 = [5, 10, 45] \\ because degree 45 is large... + @eprog + +Function: mfsturm +Class: basic +Section: modular_forms +C-Name: mfsturm +Prototype: lG +Help: mfsturm(NK): Sturm bound for modular forms on G_0(N) and + weight k, i.e., an upper bound for the order of the zero at infinity of + a nonzero form. NK is either [N,k] or an mfinit (exact bound in the + latter case). +Doc: Gives the Sturm bound for modular forms on $\Gamma_{0}(N)$ and + weight $k$, i.e., an upper bound for the order of the zero at infinity of + a nonzero form. \kbd{NK} is either + + \item a pair $[N,k]$, in which case the bound is the floor of $(kN/12) \cdot \prod_{p\mid N} (1+1/p)$; + + \item or the output of \tet{mfinit} in which case the exact upper bound is returned. + + \bprog + ? NK = [96,6]; mfsturm(NK) + %1 = 97 + ? mf=mfinit(NK,1); mfsturm(mf) + %2 = 76 + ? mfdim(NK,0) \\ new space + %3 = 72 + @eprog + +Function: mfsymbol +Class: basic +Section: modular_forms +C-Name: mfsymbol +Prototype: GDGb +Help: mfsymbol(mf,f): Initialize data for working with all period + polynomials of the modular form f: this is essential for efficiency + for functions such as mfsymboleval, mfmanin, and mfpetersson. By abuse + of language, initialize data for working with mfpetersson in weight 1 + or half-integral weight (where no symbol exist). +Doc: Initialize data for working with all period polynomials of the modular + form $f$: this is essential for efficiency for functions such as + \kbd{mfsymboleval}, \kbd{mfmanin}, and \kbd{mfpetersson}. An \kbd{mfsymbol} + contains an \kbd{mf} structure and can always be used whenever an \kbd{mf} + would be needed. + \bprog + ? mf=mfinit([23,2],0);F=mfeigenbasis(mf)[1]; + ? FS=mfsymbol(mf,F); + ? mfsymboleval(FS,[0,oo]) + %3 = [8.762565143790690142 E-39 + 0.0877907874...*I, + -5.617375463602574564 E-39 + 0.0716801031...*I] + ? mfpetersson(FS) + %4 = + [0.0039488965740025031688548076498662860143 1.2789721111175127425 E-40] + + [1.2630501762985554269 E-40 0.0056442542987647835101583821368582485396] + @eprog\noindent + By abuse of language, initialize data for working with \kbd{mfpetersson} in + weight $1$ and half-integral weight (where no symbol exist); the \kbd{mf} + argument may be an \kbd{mfsymbol} attached to a form on the space, + which avoids recomputing data independent of the form. + \bprog + ? mf=mfinit([12,9/2],1); F=mfbasis(mf); + ? fs=mfsymbol(mf,F[1]); + time = 476 ms + ? mfpetersson(fs) + %2 = 1.9722437519492014682047692073275406145 E-5 + ? f2s = mfsymbol(mf,F[2]); + time = 484 ms. + ? mfpetersson(f2s) + %4 = 1.2142222531326333658647877864573002476 E-5 + ? gs = mfsymbol(fs,F[2]); \\ re-use existing symbol, a little faster + time = 430 ms. + ? mfpetersson(gs) == %4 \\ same value + %6 = 1 + @eprog For simplicity, we also allow \kbd{mfsymbol(f)} instead of + \kbd{mfsymbol(mfinit(f), f)}: + +Function: mfsymboleval +Class: basic +Section: modular_forms +C-Name: mfsymboleval +Prototype: GGDGb +Help: mfsymboleval(fs,path,{ga=id}): evaluation of the modular + symbol fs output by mfsymbol on the given path, where path is either a vector + [s1,s2] or an integral matrix [a,b;c,d] representing the path [a/c,b/d]. + In both cases, s1 or s2 (or a/c or b/d) can also be elements of the upper + half-plane. The result is the polynomial equal to the integral between s1 and + s2 of (X-tau)^{k-2}F(tau). If ga in GL_2+(Q) is given, replace F by F|_k ga. + If the integral diverges, the result will be a rational function. +Doc: evaluation of the modular symbol $fs$ (corresponding to the modular + form $f$) output by \kbd{mfsymbol} on the given path \kbd{path}, where + \kbd{path} is either a vector $[s_{1},s_{2}]$ or an integral matrix $[a,b;c,d]$ + representing the path $[a/c,b/d]$. In both cases $s_{1}$ or $s_{2}$ + (or $a/c$ or $b/d$) can also be elements of the upper half-plane. + To avoid possibly lengthy \kbd{mfsymbol} computations, the program also + accepts $fs$ of the form \kbd{[mf,F]}, but in that case $s_{1}$ and $s_{2}$ + are limited to \kbd{oo} and elements of the upper half-plane. + The result is the polynomial equal to + $\int_{s_{1}}^{s_{2}}(X-\tau)^{k-2}F(\tau)\,d\tau$, the integral being + computed along a geodesic joining $s_{1}$ and $s_{2}$. If \kbd{ga} in + $GL_{2}^{+}(\Q)$ + is given, replace $F$ by $F|_{k}\gamma$. Note that if the integral diverges, + the result will be a rational function. + If the field of definition $\Q(f)$ is larger than $\Q(\chi)$ then $f$ can be + embedded into $\C$ in $d=[\Q(f):\Q(\chi)]$ ways, in which case a vector of + the $d$ results is returned. + \bprog + ? mf=mfinit([35,2],1);f=mfbasis(mf)[1];fs=mfsymbol(mf,f); + ? mfsymboleval(fs,[0,oo]) + %1 = 0.31404011074188471664161704390256378537*I + ? mfsymboleval(fs,[1,3;2,5]) + %2 = -0.1429696291... - 0.2619975641...*I + ? mfsymboleval(fs,[I,2*I]) + %3 = 0.00088969563028739893631700037491116258378*I + ? E2=mfEk(2);E22=mflinear([E2,mfbd(E2,2)],[1,-2]);mf=mfinit(E22); + ? E2S = mfsymbol(mf,E22); + ? mfsymboleval(E2S,[0,1]) + %6 = (-1.00000...*x^2 + 1.00000...*x - 0.50000...)/(x^2 - x) + @eprog + The rational function which is given in case the integral diverges is + easy to interpret. For instance: + \bprog + ? E4=mfEk(4);mf=mfinit(E4);ES=mfsymbol(mf,E4); + ? mfsymboleval(ES,[I,oo]) + %2 = 1/3*x^3 - 0.928067...*I*x^2 - 0.833333...*x + 0.234978...*I + ? mfsymboleval(ES,[0,I]) + %3 = (-0.234978...*I*x^3 - 0.833333...*x^2 + 0.928067...*I*x + 0.333333...)/x + @eprog\noindent + \kbd{mfsymboleval(ES,[a,oo])} is the limit as $T\to\infty$ of + $$\int_{a}^{iT}(X-\tau)^{k-2}F(\tau)\,d\tau + a(0)(X-iT)^{k-1}/(k-1)\;,$$ + where $a(0)$ is the $0$th coefficient of $F$ at infinity. Similarly, + \kbd{mfsymboleval(ES,[0,a])} is the limit as $T\to\infty$ of + $$\int_{i/T}^{a}(X-\tau)^{k-2}F(\tau)\,d\tau+b(0)(1+iTX)^{k-1}/(k-1)\;,$$ + where $b(0)$ is the $0$th coefficient of $F|_{k} S$ at infinity. + +Function: mftaylor +Class: basic +Section: modular_forms +C-Name: mftaylor +Prototype: GLD0,L,p +Help: mftaylor(F,n,{flreal=0}): F being a modular form in M_k(SL_2(Z)), + computes the first n+1 canonical Taylor expansion of F around tau=I. If + flreal=0, computes only an algebraic equivalence class. If flreal is set, + compute p_n such that for tau close enough to I we have + f(tau)=(2I/(tau+I))^ksum_{n>=0}p_n((tau-I)/(tau+I))^n. +Doc: $F$ being a form in $M_{k}(SL_{2}(\Bbb Z))$, computes the first $n+1$ + canonical Taylor expansion of $F$ around $\tau=I$. If \kbd{flreal=0}, + computes only an algebraic equivalence class. If \kbd{flreal} is set, + compute $p_{n}$ such that for $\tau$ close enough to $I$ we have + $$f(\tau)=(2I/(\tau+I))^{k}\sum_{n>=0}p_{n}((\tau-I)/(\tau+I))^{n}\;.$$ + \bprog + ? D=mfDelta(); + ? mftaylor(D,8) + %2 = [1/1728, 0, -1/20736, 0, 1/165888, 0, 1/497664, 0, -11/3981312] + @eprog + +Function: mftobasis +Class: basic +Section: modular_forms +C-Name: mftobasis +Prototype: GGD0,L, +Help: mftobasis(mf,F,{flag=0}): coefficients of the form F on the + basis given by the mfbasis(mf). A q-expansion or vector of + coefficients can also be given instead of F, but in this case an error + message may occur if the expansion is too short. An error message is also + given if F does not belong to the modular form space. If flag is set, instead + of error messages return an output as an affine space of solutions if + a q-expansion or vector of coefficients is given, or the empty column + otherwise. +Doc: coefficients of the form $F$ on the basis given by \kbd{mfbasis(mf)}. + A $q$-expansion or vector of coefficients + can also be given instead of $F$, but in this case an error message may occur + if the expansion is too short. An error message is also given if $F$ does not + belong to the modular form space. If $\fl$ is set, instead of + error messages the output is an affine space of solutions if a $q$-expansion + or vector of coefficients is given, or the empty column otherwise. + \bprog + ? mf = mfinit([26,2],0); mfdim(mf) + %1 = 2 + ? F = mflinear(mf,[a,b]); mftobasis(mf,F) + %2 = [a, b]~ + @eprog + A $q$-expansion or vector of coefficients can also be given instead of $F$. + \bprog + ? Th = 1 + 2*sum(n=1, 8, q^(n^2), O(q^80)); + ? mf = mfinit([4,5,Mod(3,4)]); + ? mftobasis(mf, Th^10) + %3 = [64/5, 4/5, 32/5]~ + @eprog + If $F$ does not belong to the corresponding space, the result is incorrect + and simply matches the coefficients of $F$ up to some bound, and + the function may either return an empty column or an error message. + If $\fl$ is set, there are no error messages, and the result is + an empty column if $F$ is a modular form; if $F$ is supplied via a series + or vector of coefficients which does not contain enough information to force + a unique (potential) solution, the function returns $[v,K]$ where $v$ is a + solution and $K$ is a matrix of maximal rank describing the affine space of + potential solutions $v + K\cdot x$. + \bprog + ? mf = mfinit([4,12],1); + ? mftobasis(mf, q-24*q^2+O(q^3), 1) + %2 = [[43/64, -63/8, 800, 21/64]~, [1, 0; 24, 0; 2048, 768; -1, 0]] + ? mftobasis(mf, [0,1,-24,252], 1) + %3 = [[1, 0, 1472, 0]~, [0; 0; 768; 0]] + ? mftobasis(mf, [0,1,-24,252,-1472], 1) + %4 = [1, 0, 0, 0]~ \\ now uniquely determined + ? mftobasis(mf, [0,1,-24,252,-1472,0], 1) + %5 = [1, 0, 0, 0]~ \\ wrong result: no such form exists + ? mfcoefs(mflinear(mf,%), 5) \\ double check + %6 = [0, 1, -24, 252, -1472, 4830] + ? mftobasis(mf, [0,1,-24,252,-1472,0]) + *** at top-level: mftobasis(mf,[0,1, + *** ^-------------------- + *** mftobasis: domain error in mftobasis: form does not belong to space + ? mftobasis(mf, mfEk(10)) + *** at top-level: mftobasis(mf,mfEk( + *** ^-------------------- + *** mftobasis: domain error in mftobasis: form does not belong to space + ? mftobasis(mf, mfEk(10), 1) + %7 = []~ + @eprog + +Function: mftocoset +Class: basic +Section: modular_forms +C-Name: mftocoset +Prototype: UGG +Help: mftocoset(N,M,Lcosets): M being a matrix in SL_2(Z) and Lcosets being + mfcosets(N), find the right coset of G_0(N) to which M belongs. The output + is a pair [ga,i] such that M = ga * Lcosets[i], with ga in G_0(N). +Doc: $M$ being a matrix in $SL_{2}(Z)$ and \kbd{Lcosets} being + \kbd{mfcosets(N)}, a list of right cosets of $\Gamma_{0}(N)$, + find the coset to which $M$ belongs. The output is a pair + $[\gamma,i]$ such that $M = \gamma \kbd{Lcosets}[i]$, $\gamma\in\Gamma_{0}(N)$. + \bprog + ? N = 4; L = mfcosets(N); + ? mftocoset(N, [1,1;2,3], L) + %2 = [[-1, 1; -4, 3], 5] + @eprog + +Function: mftonew +Class: basic +Section: modular_forms +C-Name: mftonew +Prototype: GG +Help: mftonew(mf,F): mf being a full or cuspidal space with parameters [N,k,chi] + and F a cusp form in that space, returns a vector of 3-component vectors + [M,d,G], where f(chi) divides M divides N, d divides N/M, and G is a + form in S_k^new(G_0(M),chi) such that F is equal to the sum of the + B(d)(G) over all these 3-component vectors. +Doc: \kbd{mf} being being a full or cuspidal space with parameters $[N,k,\chi]$ + and $F$ a cusp form in that space, returns a vector of 3-component vectors + $[M,d,G]$, where $f(\chi)\mid M\mid N$, $d\mid N/M$, and $G$ is a form + in $S_{k}^{\text{new}}(\Gamma_{0}(M),\chi)$ such that $F$ is equal to the sum + of the $B(d)(G)$ over all these 3-component vectors. + \bprog + ? mf = mfinit([96,6],1); F = mfbasis(mf)[60]; s = mftonew(mf,F); #s + %1 = 1 + ? [M,d,G] = s[1]; [M,d] + %2 = [48, 2] + ? mfcoefs(F,10) + %3 = [0, 0, -160, 0, 0, 0, 0, 0, 0, 0, -14400] + ? mfcoefs(G,10) + %4 = [0, 0, -160, 0, 0, 0, 0, 0, 0, 0, -14400] + @eprog + +Function: mftraceform +Class: basic +Section: modular_forms +C-Name: mftraceform +Prototype: GD0,L, +Help: mftraceform(NK,{space=0}): If NK=[N,k,CHI,.] as in + mfinit with k integral, gives the trace form in the corresponding subspace + of S_k(G_0(N),chi). The supported values for space are 0: the newspace + (default), 1: the full cuspidal space. +Doc: If $NK=[N,k,CHI,.]$ as in \kbd{mfinit} with $k$ integral, gives the + trace form in the corresponding subspace of $S_{k}(\Gamma_{0}(N),\chi)$. + The supported values for \kbd{space} are 0: the newspace (default), + 1: the full cuspidal space. + \bprog + ? F = mftraceform([23,2]); mfcoefs(F,16) + %1 = [0, 2, -1, 0, -1, -2, -5, 2, 0, 4, 6, -6, 5, 6, 4, -10, -3] + ? F = mftraceform([23,1,-23]); mfcoefs(F,16) + %2 = [0, 1, -1, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0, -1] + @eprog + +Function: mftwist +Class: basic +Section: modular_forms +C-Name: mftwist +Prototype: GG +Help: mftwist(F,D): returns the twist of the form F by the + integer D, i.e., the form G such that mfcoef(G,n)=(D/n)mfcoef(F,n), + where (D/n) is the Kronecker symbol. +Doc: $F$ being a generalized modular form, returns the twist of $F$ by the + integer $D$, i.e., the form $G$ such that + \kbd{mfcoef(G,n)=}$(D/n)$\kbd{mfcoef(F,n)}, where $(D/n)$ is the Kronecker + symbol. + \bprog + ? mf = mfinit([11,2],0); F = mfbasis(mf)[1]; mfcoefs(F, 5) + %1 = [0, 1, -2, -1, 2, 1] + ? G = mftwist(F,-3); mfcoefs(G, 5) + %2 = [0, 1, 2, 0, 2, -1] + ? mf2 = mfinit([99,2],0); mftobasis(mf2, G) + %3 = [1/3, 0, 1/3, 0]~ + @eprog\noindent Note that twisting multiplies the level by $D^{2}$. In + particular it is not an involution: + \bprog + ? H = mftwist(G,-3); mfcoefs(H, 5) + %4 = [0, 1, -2, 0, 2, 1] + ? mfparams(G) + %5 = [99, 2, 1, y, t - 1] + @eprog + +Function: min +Class: basic +Section: operators +C-Name: gmin +Prototype: GG +Help: min(x,y): minimum of x and y. +Description: + (small, small):small minss($1, $2) + (small, int):int gminsg($1, $2) + (int, small):int gmings($1, $2) + (int, int):int gmin($1, $2) + (small, mp):mp gminsg($1, $2) + (mp, small):mp gmings($1, $2) + (mp, mp):mp gmin($1, $2) + (small, gen):gen gminsg($1, $2) + (gen, small):gen gmings($1, $2) + (gen, gen):gen gmin($1, $2) +Doc: creates the minimum of $x$ and $y$ when they can be compared. + +Function: minpoly +Class: basic +Section: linear_algebra +C-Name: minpoly +Prototype: GDn +Help: minpoly(A,{v='x}): minimal polynomial of the matrix or polmod A. +Doc: \idx{minimal polynomial} + of $A$ with respect to the variable $v$., i.e. the monic polynomial $P$ + of minimal degree (in the variable $v$) such that $P(A) = 0$. + +Function: modreverse +Class: basic +Section: number_fields +C-Name: modreverse +Prototype: G +Help: modreverse(z): reverse polmod of the polmod z, if it exists. +Doc: let $z = \kbd{Mod(A, T)}$ be a polmod, and $Q$ be its minimal + polynomial, which must satisfy $\text{deg}(Q) = \text{deg}(T)$. + Returns a ``reverse polmod'' \kbd{Mod(B, Q)}, which is a root of $T$. + + This is quite useful when one changes the generating element in algebraic + extensions: + \bprog + ? u = Mod(x, x^3 - x -1); v = u^5; + ? w = modreverse(v) + %2 = Mod(x^2 - 4*x + 1, x^3 - 5*x^2 + 4*x - 1) + @eprog\noindent + which means that $x^{3} - 5x^{2} + 4x -1$ is another defining polynomial + for the cubic field + $$\Q(u) = \Q[x]/(x^{3} - x - 1) = \Q[x]/(x^{3} - 5x^{2} + 4x - 1) = \Q(v),$$ + and that $u \to v^{2} - 4v + 1$ gives an explicit isomorphism. From this, it is + easy to convert elements between the $A(u)\in \Q(u)$ and $B(v)\in \Q(v)$ + representations: + \bprog + ? A = u^2 + 2*u + 3; subst(lift(A), 'x, w) + %3 = Mod(x^2 - 3*x + 3, x^3 - 5*x^2 + 4*x - 1) + ? B = v^2 + v + 1; subst(lift(B), 'x, v) + %4 = Mod(26*x^2 + 31*x + 26, x^3 - x - 1) + @eprog + If the minimal polynomial of $z$ has lower degree than expected, the routine + fails + \bprog + ? u = Mod(-x^3 + 9*x, x^4 - 10*x^2 + 1) + ? modreverse(u) + *** modreverse: domain error in modreverse: deg(minpoly(z)) < 4 + *** Break loop: type 'break' to go back to GP prompt + break> Vec( dbg_err() ) \\ ask for more info + ["e_DOMAIN", "modreverse", "deg(minpoly(z))", "<", 4, + Mod(-x^3 + 9*x, x^4 - 10*x^2 + 1)] + break> minpoly(u) + x^2 - 8 + @eprog + +Function: moebius +Class: basic +Section: number_theoretical +C-Name: moebius +Prototype: lG +Help: moebius(x): Moebius function of x. +Doc: \idx{Moebius} $\mu$-function of $|x|$; $x$ must be a nonzero integer. + +Function: msatkinlehner +Class: basic +Section: modular_symbols +C-Name: msatkinlehner +Prototype: GLDG +Help: msatkinlehner(M,Q,{H}): M being a full modular symbol space of level N, + as given by msinit, let Q | N, (Q,N/Q) = 1, and let H be a subspace stable + under the Atkin-Lehner involution w_Q. Return the matrix of w_Q + acting on H (M if omitted). +Doc: Let $M$ be a full modular symbol space of level $N$, + as given by \kbd{msinit}, let $Q \mid N$, $(Q,N/Q) = 1$, + and let $H$ be a subspace stable under the Atkin-Lehner involution $w_{Q}$. + Return the matrix of $w_{Q}$ acting on $H$ ($M$ if omitted). + \bprog + ? M = msinit(36,2); \\ M_2(Gamma_0(36)) + ? w = msatkinlehner(M,4); w^2 == 1 + %2 = 1 + ? #w \\ involution acts on a 13-dimensional space + %3 = 13 + ? M = msinit(36,2, -1); \\ M_2(Gamma_0(36))^- + ? w = msatkinlehner(M,4); w^2 == 1 + %5 = 1 + ? #w + %6 = 4 + @eprog + +Function: mscosets +Class: basic +Section: modular_symbols +C-Name: mscosets0 +Prototype: GG +Help: mscosets(gen,inH): gen being a system of generators for a group G and H + being a subgroup of finite index of G, return a list of right cosets of H \ G + and the right action of G on H \ G. The subgroup H is given by a criterion inH + (closure) deciding whether an element of G belongs to H. +Doc: \kbd{gen} being a system of generators for a group $G$ and $H$ being a + subgroup of finite index in $G$, return a list of right cosets of + $H\backslash G$ and the right action of $G$ on $H\backslash G$. The subgroup + $H$ is given by a criterion \kbd{inH} (closure) deciding whether an element + of $G$ belongs to $H$. The group $G$ is restricted to types handled by generic + multiplication (\kbd{*}) and inversion (\kbd{g\pow (-1)}), such as matrix + groups or permutation groups. + + Let $\kbd{gens} = [g_{1}, \dots, g_{r}]$. The function returns $[C,M]$ where $C$ + lists the $h = [G:H]$ representatives $[\gamma_{1}, \dots, \gamma_{h}]$ + for the right cosets $H\gamma_{1},\dots,H\gamma_{h}$; $\gamma_{1}$ is always + the neutral element in $G$. For all $i \leq h$, $j \leq r$, if $M[i][j] = k$ + then $H \gamma_{i} g_{j} = H\gamma_{k}$. + \bprog + ? PSL2 = [[0,1;-1,0], [1,1;0,1]]; \\ S and T + \\ G = PSL2, H = Gamma0(2) + ? [C, M] = mscosets(PSL2, g->g[2,1] % 2 == 0); + ? C \\ three cosets + %3 = [[1, 0; 0, 1], [0, 1; -1, 0], [0, 1; -1, -1]] + ? M + %4 = [Vecsmall([2, 1]), Vecsmall([1, 3]), Vecsmall([3, 2])] + @eprog\noindent Looking at $M[1]$ we see that $S$ belongs to the second + coset and $T$ to the first (trivial) coset. +Variant: Also available is the function + \fun{GEN}{mscosets}{GEN G, void *E, long (*inH)(void *, GEN)} + +Function: mscuspidal +Class: basic +Section: modular_symbols +C-Name: mscuspidal +Prototype: GD0,L, +Help: mscuspidal(M,{flag=0}): M being a full modular symbol space, as given + by msinit, return its cuspidal part S. If flag = 1, return [S,E] its + decomposition into Eisenstein and cuspidal parts. +Doc: + $M$ being a full modular symbol space, as given by \kbd{msinit}, + return its cuspidal part $S$. If $\fl = 1$, return + $[S,E]$ its decomposition into cuspidal and Eisenstein parts. + + A subspace is given by a structure allowing quick projection and + restriction of linear operators; its first component is + a matrix with integer coefficients whose columns form a $\Q$-basis of + the subspace. + \bprog + ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ + ? [S,E] = mscuspidal(M, 1); + ? E[1] \\ 2-dimensional + %3 = + [0 -10] + + [0 -15] + + [0 -3] + + [1 0] + + ? S[1] \\ 1-dimensional + %4 = + [ 3] + + [30] + + [ 6] + + [-8] + @eprog + +Function: msdim +Class: basic +Section: modular_symbols +C-Name: msdim +Prototype: lG +Help: msdim(M): M being a modular symbol space or subspace, + return its dimension as a Q-vector space. +Doc: $M$ being a full modular symbol space or subspace, for instance + as given by \kbd{msinit} or \kbd{mscuspidal}, return + its dimension as a $\Q$-vector space. + \bprog + ? M = msinit(11,4); msdim(M) + %1 = 6 + ? M = msinit(11,4,1); msdim(M) + %2 = 4 \\ dimension of the '+' part + ? [S,E] = mscuspidal(M,1); + ? [msdim(S), msdim(E)] + %4 = [2, 2] + @eprog\noindent Note that \kbd{mfdim([N,k])} is going to be much faster if + you only need the dimension of the space and not really to work with it. + This function is only useful to quickly check the dimension of an existing + space. + +Function: mseisenstein +Class: basic +Section: modular_symbols +C-Name: mseisenstein +Prototype: G +Help: mseisenstein(M): M being a full modular symbol space, as given by msinit, + return its Eisenstein subspace. +Doc: + $M$ being a full modular symbol space, as given by \kbd{msinit}, + return its Eisenstein subspace. + A subspace is given by a structure allowing quick projection and + restriction of linear operators; its first component is + a matrix with integer coefficients whose columns form a $\Q$-basis of + the subspace. + This is the same basis as given by the second component of + \kbd{mscuspidal}$(M, 1)$. + \bprog + ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ + ? E = mseisenstein(M); + ? E[1] \\ 2-dimensional + %3 = + [0 -10] + + [0 -15] + + [0 -3] + + [1 0] + + ? E == mscuspidal(M,1)[2] + %4 = 1 + @eprog + +Function: mseval +Class: basic +Section: modular_symbols +C-Name: mseval +Prototype: GGDG +Help: mseval(M,s,{p}): M being a full modular symbol space, as given by + msinit, s being a modular symbol from M and p being a path between two + elements in P^1(Q), return s(p). +Doc: Let $\Delta_{0}:=\text{Div}^{0}(\P^{1} (\Q))$. + Let $M$ be a full modular symbol space, as given by \kbd{msinit}, + let $s$ be a modular symbol from $M$, i.e. an element + of $\Hom_{G}(\Delta_{0}, V)$, and let $p=[a,b] \in \Delta_{0}$ be a path between + two elements in $\P^{1}(\Q)$, return $s(p)\in V$. The path extremities $a$ and + $b$ may be given as \typ{INT}, \typ{FRAC} or $\kbd{oo} = (1:0)$; it + is also possible to describe the path by a $2 \times 2$ integral matrix + whose columns give the two cusps. The symbol $s$ is either + + \item a \typ{COL} coding a modular symbol in terms of + the fixed basis of $\Hom_{G}(\Delta_{0},V)$ chosen in $M$; if $M$ was + initialized with a nonzero \emph{sign} ($+$ or $-$), then either the + basis for the full symbol space or the $\pm$-part can be used (the dimension + being used to distinguish the two). + + \item a \typ{MAT} whose columns encode modular symbols as above. This is + much faster than evaluating individual symbols on the same path $p$ + independently. + + \item a \typ{VEC} $(v_{i})$ of elements of $V$, where the $v_{i} = s(g_{i})$ + give + the image of the generators $g_{i}$ of $\Delta_{0}$, see \tet{mspathgens}. + We assume that $s$ is a proper symbol, i.e.~that the $v_{i}$ satisfy + the \kbd{mspathgens} relations. + + If $p$ is omitted, convert a single symbol $s$ to the second form: a vector + of the $s(g_{i})$. A \typ{MAT} is converted to a vector of such. + \bprog + ? M = msinit(2,8,1); \\ M_8(Gamma_0(2))^+ + ? g = mspathgens(M)[1] + %2 = [[+oo, 0], [0, 1]] + ? N = msnew(M)[1]; #N \\ Q-basis of new subspace, dimension 1 + %3 = 1 + ? s = N[,1] \\ t_COL representation + %4 = [-3, 6, -8]~ + ? S = mseval(M, s) \\ t_VEC representation + %5 = [64*x^6-272*x^4+136*x^2-8, 384*x^5+960*x^4+192*x^3-672*x^2-432*x-72] + ? mseval(M,s, g[1]) + %6 = 64*x^6 - 272*x^4 + 136*x^2 - 8 + ? mseval(M,S, g[1]) + %7 = 64*x^6 - 272*x^4 + 136*x^2 - 8 + @eprog\noindent Note that the symbol should have values in + $V = \Q[x,y]_{k-2}$, we return the de-homogenized values corresponding to $y + = 1$ instead. + +Function: msfarey +Class: basic +Section: modular_symbols +C-Name: msfarey0 +Prototype: GGD& +Help: msfarey(F,inH,{&CM}): F being a Farey symbol attached to a group G + contained in SL2(Z) and H a subgroup of G, return a Farey symbol attached + to H; H is given by a criterion inH (closure) deciding whether an element + of G belongs to H. +Doc: + $F$ being a Farey symbol attached to a group $G$ contained in + $\text{PSL}_{2}(\Z)$ and $H$ a subgroup of $G$, return a Farey symbol attached + to $H$. The subgroup $H$ is given by a criterion \kbd{inH} (closure) deciding + whether an element of $G$ belongs to $H$. The symbol $F$ can be created using + + \item \kbd{mspolygon}: $G = \Gamma_{0}(N)$, which runs in time $\tilde{O}(N)$; + + \item or \kbd{msfarey} itself, which runs in time $O([G:H]^{2})$. + + If present, the argument \kbd{CM} is set to \kbd{mscosets(F[3])}, giving + the right cosets of $H \backslash G$ and the action of $G$ by right + multiplication. Since \kbd{msfarey}'s algorithm is quadratic in the index + $[G:H]$, it is advisable to construct subgroups by a chain of inclusions if + possible. + + \bprog + \\ Gamma_0(N) + G0(N) = mspolygon(N); + + \\ Gamma_1(N): direct construction, slow + G1(N) = msfarey(mspolygon(1), g -> my(a = g[1,1]%N, c = g[2,1]%N);\ + c == 0 && (a == 1 || a == N-1)); + \\ Gamma_1(N) via Gamma_0(N): much faster + G1(N) = msfarey(G0(N), g -> my(a=g[1,1]%N); a==1 || a==N-1); + @eprog\noindent Note that the simpler criterion \kbd{g[1,1]\%N == 1} would not + be correct since it must apply to elements of $\text{PSL}_{2}(\Z)$ hence be + invariant under $g \mapsto -g$. Here are other examples: + \bprog + \\ Gamma(N) + G(N) = msfarey(G1(N), g -> g[1,2]%N==0); + + G_00(N) = msfarey(G0(N), x -> x[1,2]%N==0); + G1_0(N1,N2) = msfarey(G0(1), x -> x[2,1]%N1==0 && x[1,2]%N2==0); + + \\ Gamma_0(91) has 4 elliptic points of order 3, Gamma_1(91) has none + D0 = mspolygon(G0(91), 2)[4]; + D1 = mspolygon(G1(91), 2)[4]; + write("F.tex","\\documentclass{article}\\usepackage{tikz}\\begin{document}",\ + D0,"\n",D1,"\\end{document}"); + @eprog +Variant: Also available is + \fun{GEN}{msfarey}{GEN F, void *E, long (*inH)(void *, GEN), GEN *pCM}. + +Function: msfromcusp +Class: basic +Section: modular_symbols +C-Name: msfromcusp +Prototype: GG +Help: msfromcusp(M,c): returns the modular symbol attached to the cusp + c, where M is a modular symbol space of level N. +Doc: returns the modular symbol attached to the cusp + $c$, where $M$ is a modular symbol space of level $N$, attached to + $G = \Gamma_{0}(N)$. The cusp $c$ in $\P^{1}(\Q)/G$ is given either as \kbd{oo} + ($=(1:0)$) or as a rational number $a/b$ ($=(a:b)$). The attached symbol maps + the path $[b] - [a] \in \text{Div}^{0} (\P^{1}(\Q))$ to $E_{c}(b) - E_{c}(a)$, + where + $E_{c}(r)$ is $0$ when $r \neq c$ and $X^{k-2} \mid \gamma_{r}$ otherwise, + where + $\gamma_{r} \cdot r = (1:0)$. These symbols span the Eisenstein subspace + of $M$. + \bprog + ? M = msinit(2,8); \\ M_8(Gamma_0(2)) + ? E = mseisenstein(M); + ? E[1] \\ two-dimensional + %3 = + [0 -10] + + [0 -15] + + [0 -3] + + [1 0] + + ? s = msfromcusp(M,oo) + %4 = [0, 0, 0, 1]~ + ? mseval(M, s) + %5 = [1, 0] + ? s = msfromcusp(M,1) + %6 = [-5/16, -15/32, -3/32, 0]~ + ? mseval(M,s) + %7 = [-x^6, -6*x^5 - 15*x^4 - 20*x^3 - 15*x^2 - 6*x - 1] + @eprog + In case $M$ was initialized with a nonzero \emph{sign}, the symbol is given + in terms of the fixed basis of the whole symbol space, not the $+$ or $-$ + part (to which it need not belong). + \bprog + ? M = msinit(2,8, 1); \\ M_8(Gamma_0(2))^+ + ? E = mseisenstein(M); + ? E[1] \\ still two-dimensional, in a smaller space + %3 = + [ 0 -10] + + [ 0 3] + + [-1 0] + + ? s = msfromcusp(M,oo) \\ in terms of the basis for M_8(Gamma_0(2)) ! + %4 = [0, 0, 0, 1]~ + ? mseval(M, s) \\ same symbol as before + %5 = [1, 0] + @eprog + +Function: msfromell +Class: basic +Section: modular_symbols +C-Name: msfromell +Prototype: GD0,L, +Help: msfromell(E,{sign=0}): return the [M, x], where M is msinit(N,2) + and x is the modular symbol in M attached to the elliptic curve E/Q. +Doc: Let $E/\Q$ be an elliptic curve of conductor $N$. For $\varepsilon = + \pm1$, we define the (cuspidal, new) modular symbol $x^{\varepsilon}$ in + $H^{1}_{c}(X_{0}(N),\Q)^{\varepsilon}$ attached to $E$. For all primes $p$ + not dividing $N$ we have + $T_{p}(x^{\varepsilon}) = a_{p} x^{\varepsilon}$, where $a_{p} = + p+1-\#E(\F_{p})$. + + Let $\Omega^{+} = \kbd{E.omega[1]}$ be the real period of $E$ + (integration of the N\'eron differential $dx/(2y+a_{1}x+a_{3})$ on the + connected + component of $E(\R)$, i.e.~the generator of $H_{1}(E,\Z)^{+}$) normalized by + $\Omega^{+}>0$. Let $i\Omega^{-}$ the integral on a generator of + $H_{1}(E,\Z)^{-}$ with + $\Omega^{-} \in \R_{>0}$. If $c_{\infty}$ is the number of connected components of + $E(\R)$, $\Omega^{-}$ is equal to $(-2/c_{\infty}) \times \kbd{imag(E.omega[2])}$. + The complex modular symbol is defined by + $$F: \delta \to 2i\pi \int_{\delta} f(z) dz$$ + The modular symbols $x^{\varepsilon}$ are normalized so that + $ F = x^{+} \Omega^{+} + x^{-} i\Omega^{-}$. In particular, we have + $$ x^{+}([0]-[\infty]) = L(E,1) / \Omega^{+},$$ + which defines $x^{\pm}$ unless $L(E,1)=0$. Furthermore, for all fundamental + discriminants $D$ such that $\varepsilon \cdot D > 0$, we also have + $$\sum_{0\leq a<|D|} (D|a) x^{\varepsilon}([a/|D|]-[\infty]) + = L(E,(D|.),1) / \Omega^{\varepsilon},$$ + where $(D|.)$ is the Kronecker symbol. The period $\Omega^{-}$ is also + $2/c_{\infty} \times$ the real period of the twist + $E^{(-4)} = \kbd{elltwist(E,-4)}$. + + This function returns the pair $[M, x]$, where $M$ is + \kbd{msinit}$(N,2)$ and $x$ is $x^{\var{sign}}$ as above when $\var{sign}= + \pm1$, and $x = [x^{+},x^{-}, L_{E}]$ when \var{sign} is $0$, where $L_{E}$ + is a matrix giving the canonical $\Z$-lattice attached to $E$ in the sense + of \kbd{mslattice} applied to $\Q x^{+} + \Q x^{-}$. Explicitly, it + is generated by $(x^{+},x^{-})$ when $E(\R)$ has two connected components + and by $(x^{+} - x^{-},2x^{-})$ otherwise. + + The modular symbols $x^{\pm}$ are given as a \typ{COL} (in terms + of the fixed basis of $\Hom_{G}(\Delta_{0},\Q)$ chosen in $M$). + \bprog + ? E=ellinit([0,-1,1,-10,-20]); \\ X_0(11) + ? [M,xp]= msfromell(E,1); + ? xp + %3 = [1/5, -1/2, -1/2]~ + ? [M,x]= msfromell(E); + ? x \\ x^+, x^- and L_E + %5 = [[1/5, -1/2, -1/2]~, [0, 1/2, -1/2]~, [1/5, 0; -1, 1; 0, -1]] + ? p = 23; (mshecke(M,p) - ellap(E,p))*x[1] + %6 = [0, 0, 0]~ \\ true at all primes, including p = 11; same for x[2] + ? (mshecke(M,p) - ellap(E,p))*x[3] == 0 + %7 = 1 + @eprog + + \noindent Instead of a single curve $E$, one may use instead a vector + of \emph{isogenous} curves. The function then returns $M$ and the + vector of attached modular symbols. + +Function: msfromhecke +Class: basic +Section: modular_symbols +C-Name: msfromhecke +Prototype: GGDG +Help: msfromhecke(M,v,{H}): given a msinit M and a vector v + of pairs [p, P] (where p is prime and P is a polynomial with integer + coefficients), return a basis of all modular symbols such that + P(Tp) * s = 0. If H is present, it must be a Hecke-stable subspace + and we restrict to s in H. +Doc: given a msinit $M$ and a vector $v$ of pairs $[p, P]$ (where $p$ is prime + and $P$ is a polynomial with integer coefficients), return a basis of all + modular symbols such that $P(T_{p})(s) = 0$. If $H$ is present, it must + be a Hecke-stable subspace and we restrict to $s \in H$. When $T_{p}$ has + a rational eigenvalue and $P(x) = x-a_{p}$ has degree $1$, we also accept the + integer $a_{p}$ instead of $P$. + \bprog + ? E = ellinit([0,-1,1,-10,-20]) \\11a1 + ? ellap(E,2) + %2 = -2 + ? ellap(E,3) + %3 = -1 + ? M = msinit(11,2); + ? S = msfromhecke(M, [[2,-2],[3,-1]]) + %5 = + [ 1 1] + + [-5 0] + + [ 0 -5] + ? mshecke(M, 2, S) + %6 = + [-2 0] + + [ 0 -2] + + ? M = msinit(23,4); + ? S = msfromhecke(M, [[5, x^4-14*x^3-244*x^2+4832*x-19904]]); + ? factor( charpoly(mshecke(M,5,S)) ) + %9 = + [x^4 - 14*x^3 - 244*x^2 + 4832*x - 19904 2] + @eprog + +Function: msgetlevel +Class: basic +Section: modular_symbols +C-Name: msgetlevel +Prototype: lG +Help: msgetlevel(M): M being a full modular symbol space, as given by msinit, return its level N. +Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return + its level $N$. + +Function: msgetsign +Class: basic +Section: modular_symbols +C-Name: msgetsign +Prototype: lG +Help: msgetsign(M): M being a full modular symbol space, as given by msinit, return its sign. +Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return + its sign: $\pm1$ or 0 (unset). + \bprog + ? M = msinit(11,4, 1); + ? msgetsign(M) + %2 = 1 + ? M = msinit(11,4); + ? msgetsign(M) + %4 = 0 + @eprog + +Function: msgetweight +Class: basic +Section: modular_symbols +C-Name: msgetweight +Prototype: lG +Help: msgetweight(M): M being a full modular symbol space, as given by msinit, return its weight k. +Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, return + its weight $k$. + \bprog + ? M = msinit(11,4); + ? msgetweight(M) + %2 = 4 + @eprog + +Function: mshecke +Class: basic +Section: modular_symbols +C-Name: mshecke +Prototype: GLDG +Help: mshecke(M,p,{H}): M being a full modular symbol space, as given by msinit, + p being a prime number, and H being a Hecke-stable subspace (M if omitted), + return the matrix of T_p acting on H (U_p if p divides the level). +Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, + $p$ being a prime number, and $H$ being a Hecke-stable subspace ($M$ if + omitted), return the matrix of $T_{p}$ acting on $H$ + ($U_{p}$ if $p$ divides $N$). Result is undefined if $H$ is not stable + by $T_{p}$ (resp.~$U_{p}$). + \bprog + ? M = msinit(11,2); \\ M_2(Gamma_0(11)) + ? T2 = mshecke(M,2) + %2 = + [3 0 0] + + [1 -2 0] + + [1 0 -2] + ? M = msinit(11,2, 1); \\ M_2(Gamma_0(11))^+ + ? T2 = mshecke(M,2) + %4 = + [ 3 0] + + [-1 -2] + + ? N = msnew(M)[1] \\ Q-basis of new cuspidal subspace + %5 = + [-2] + + [-5] + + ? p = 1009; mshecke(M, p, N) \\ action of T_1009 on N + %6 = + [-10] + ? ellap(ellinit("11a1"), p) + %7 = -10 + @eprog + +Function: msinit +Class: basic +Section: modular_symbols +C-Name: msinit +Prototype: GGD0,L, +Help: msinit(G,V,{sign=0}): given G a finite index subgroup of SL(2,Z) + and a finite dimensional representation V of GL(2,Q), creates a space of + modular symbols, the G-module Hom_G(Div^0(P^1 Q), V). This is canonically + isomorphic to H^1_c(X(G), V), and allows to compute modular forms for G. + If sign is present and nonzero, it must be +1 or -1 and we consider + the subspace defined by Ker (Sigma - sign), where Sigma is induced by + [-1,0;0,1]. Currently the only supported groups are the Gamma_0(N), coded by + the integer N. The only supported representation is V_k = Q[X,Y]_{k-2}, coded + by the integer k >= 2. +Doc: given $G$ a finite index subgroup of $\text{SL}(2,\Z)$ + and a finite dimensional representation $V$ of $\text{GL}(2,\Q)$, creates a + space of modular symbols, the $G$-module + $\Hom_{G}(\text{Div}^{0}(\P^{1}(\Q)), V)$. + This is canonically isomorphic to $H^{1}_{c}(X(G), V)$, and allows to + compute modular forms for $G$. If \emph{sign} is present and nonzero, it + must be $\pm1$ and we consider the subspace defined by $\text{Ker} (\sigma - + \var{sign})$, where $\sigma$ is induced by \kbd{[-1,0;0,1]}. Currently the + only supported groups are the $\Gamma_{0}(N)$, coded by the integer $N > 0$. + The only supported representation is $V_{k} = \Q[X,Y]_{k-2}$, coded by the + integer $k \geq 2$. + \bprog + ? M = msinit(11,2); msdim(M) \\ Gamma0(11), weight 2 + %1 = 3 + ? mshecke(M,2) \\ T_2 acting on M + %2 = + [3 1 1] + + [0 -2 0] + + [0 0 -2] + ? msstar(M) \\ * involution + %3 = + [1 0 0] + + [0 0 1] + + [0 1 0] + + ? Mp = msinit(11,2, 1); msdim(Mp) \\ + part + %4 = 2 + ? mshecke(Mp,2) \\ T_2 action on M^+ + %5 = + [3 2] + + [0 -2] + ? msstar(Mp) + %6 = + [1 0] + + [0 1] + @eprog + +Function: msissymbol +Class: basic +Section: modular_symbols +C-Name: msissymbol +Prototype: GG +Help: msissymbol(M,s): M being a full modular symbol space, as given by msinit, + check whether s is a modular symbol attached to M. +Doc: + $M$ being a full modular symbol space, as given by \kbd{msinit}, + check whether $s$ is a modular symbol attached to $M$. If $A$ is a matrix, + check whether its columns represent modular symbols and return a $0-1$ + vector. + \bprog + ? M = msinit(7,8, 1); \\ M_8(Gamma_0(7))^+ + ? A = msnew(M)[1]; + ? s = A[,1]; + ? msissymbol(M, s) + %4 = 1 + ? msissymbol(M, A) + %5 = [1, 1, 1] + ? S = mseval(M,s); + ? msissymbol(M, S) + %7 = 1 + ? [g,R] = mspathgens(M); g + %8 = [[+oo, 0], [0, 1/2], [1/2, 1]] + ? #R \\ 3 relations among the generators g_i + %9 = 3 + ? T = S; T[3]++; \\ randomly perturb S(g_3) + ? msissymbol(M, T) + %11 = 0 \\ no longer satisfies the relations + @eprog + +Function: mslattice +Class: basic +Section: modular_symbols +C-Name: mslattice +Prototype: GDG +Help: mslattice(M,{H}): M being a full modular symbol space, + as given by msinit, H a Q-subspace or a matrix of modular symbols. + Return the canonical integral structure of H. +Doc: Let $\Delta_{0}:=\text{Div}^{0}(\P^{1}(\Q))$ and $V_{k} = \Q[x,y]_{k-2}$. + Let $M$ be a full modular symbol space, as given by \kbd{msinit} + and let $H$ be a subspace, e.g. as given by \kbd{mscuspidal}. + This function returns a canonical $\Z$-structure on $H$ defined as follows. + Consider the map $c: M=\Hom_{\Gamma_{0}(N)}(\Delta_{0}, V_{k}) \to + H^{1}(\Gamma_{0}(N), V_{k})$ given by + $\phi \mapsto \var{class}(\gamma \to \phi(\{0, \gamma^{-1} 0\}))$. + Let $L_{k}=\Z[x,y]_{k-2}$ be the natural $\Z$-structure of $V_{k}$. + The result of + \kbd{mslattice} is a $\Z$-basis of the inverse image by $c$ of + $H^{1}(\Gamma_{0}(N), L_{k})$ in the space of modular symbols generated by $H$. + + For user convenience, $H$ can be defined by a matrix representing the + $\Q$-basis of $H$ (in terms of the canonical $\Q$-basis of $M$ fixed by + \kbd{msinit} and used to represent modular symbols). + + If omitted, $H$ is the cuspidal part of $M$ as given by \kbd{mscuspidal}. + The Eisenstein part $\Hom_{\Gamma_{0}(N)}(\text{Div}(\P^{1}(\Q)), V_{k})$ is in + the kernel of $c$, so the result has no meaning for the Eisenstein part + \kbd{H}. + + \bprog + ? M=msinit(11,2); + ? [S,E] = mscuspidal(M,1); S[1] \\ a primitive Q-basis of S + %2 = + [ 1 1] + [-5 0] + [ 0 -5] + ? mslattice(M,S) + %3 = + [-1/5 -1/5] + [ 1 0] + [ 0 1] + ? mslattice(M,E) + %4 = + [1] + [0] + [0] + ? M=msinit(5,4); + ? S=mscuspidal(M); S[1] + %6 = + [ 7 20] + [ 3 3] + [-10 -23] + [-30 -30] + ? mslattice(M,S) + %7 = + [-1/10 -11/130] + [ 0 -1/130] + [ 1/10 6/65] + [ 0 1/13] + @eprog + +Function: msnew +Class: basic +Section: modular_symbols +C-Name: msnew +Prototype: G +Help: msnew(M): M being a full modular symbol space, as given by msinit, + return its new cuspidal subspace. +Doc: + $M$ being a full modular symbol space, as given by \kbd{msinit}, + return the \emph{new} part of its cuspidal subspace. A subspace is given by + a structure allowing quick projection and restriction of linear operators; + its first component is a matrix with integer coefficients whose columns form + a $\Q$-basis of the subspace. + \bprog + ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ + ? N = msnew(M); + ? #N[1] \\ 6-dimensional + %3 = 6 + @eprog + +Function: msomseval +Class: basic +Section: modular_symbols +C-Name: msomseval +Prototype: GGG +Help: msomseval(Mp,PHI,path): + return the vectors of moments of the p-adic distribution attached + to the path 'path' via the overconvergent modular symbol 'PHI'. +Doc: return the vectors of moments of the $p$-adic distribution attached + to the path \kbd{path} by the overconvergent modular symbol \kbd{PHI}. + \bprog + ? M = msinit(3,6,1); + ? Mp= mspadicinit(M,5,10); + ? phi = [5,-3,-1]~; + ? msissymbol(M,phi) + %4 = 1 + ? PHI = mstooms(Mp,phi); + ? ME = msomseval(Mp,PHI,[oo, 0]); + @eprog + +Function: mspadicL +Class: basic +Section: modular_symbols +C-Name: mspadicL +Prototype: GDGD0,L, +Help: mspadicL(mu,{s=0},{r=0}): given + mu from mspadicmoments (p-adic distributions attached to an + overconvergent symbol PHI) returns the value on a + character of Z_p^* represented by s of the derivative of order r of the + p-adic L-function attached to PHI. +Doc: Returns the value (or $r$-th derivative) + on a character $\chi^{s}$ of $\Z_{p}^{*}$ of the $p$-adic $L$-function + attached to \kbd{mu}. + + Let $\Phi$ be the $p$-adic distribution-valued overconvergent symbol + attached to a modular symbol $\phi$ for $\Gamma_{0}(N)$ (eigenvector for + $T_{N}(p)$ for the eigenvalue $a_{p}$). + Then $L_{p}(\Phi,\chi^{s})=L_{p}(\mu,s)$ is the + $p$-adic $L$ function defined by + $$L_{p}(\Phi,\chi^{s})= \int_{\Z_{p}^{*}} \chi^{s}(z) d\mu(z)$$ + where $\mu$ is the distribution on $\Z_{p}^{*}$ defined by the restriction of + $\Phi([\infty]-[0])$ to $\Z_{p}^{*}$. The $r$-th derivative is taken in + direction $\langle \chi\rangle$: + $$L_{p}^{(r)}(\Phi,\chi^{s})= \int_{\Z_{p}^{*}} \chi^{s}(z) + (\log z)^{r} d\mu(z).$$ + In the argument list, + + \item \kbd{mu} is as returned by \tet{mspadicmoments} (distributions + attached to $\Phi$ by restriction to discs $a + p^{\nu}\Z_{p}$, $(a,p)=1$). + + \item $s=[s_{1},s_{2}]$ with $s_{1} \in \Z \subset \Z_{p}$ and + $s_{2} \bmod p-1$ or + $s_{2} \bmod 2$ for $p=2$, encoding the $p$-adic character $\chi^{s} := + \langle \chi \rangle^{s_{1}} \tau^{s_{2}}$; here $\chi$ is the cyclotomic + character from $\text{Gal}(\Q_{p}(\mu_{p^{\infty}})/\Q_{p})$ to $\Z_{p}^{*}$, + and $\tau$ is the Teichm\"uller character (for $p>2$ and the character of + order 2 on $(\Z/4\Z)^{*}$ if $p=2$); for convenience, the character $[s,s]$ + can also be represented by the integer $s$. + + When $a_{p}$ is a $p$-adic unit, $L_{p}$ takes its values in $\Q_{p}$. + When $a_{p}$ is not a unit, it takes its values in the + two-dimensional $\Q_{p}$-vector space $D_{cris}(M(\phi))$ where $M(\phi)$ is + the ``motive'' attached to $\phi$, and we return the two $p$-adic components + with respect to some fixed $\Q_{p}$-basis. + \bprog + ? M = msinit(3,6,1); phi=[5, -3, -1]~; + ? msissymbol(M,phi) + %2 = 1 + ? Mp = mspadicinit(M, 5, 4); + ? mu = mspadicmoments(Mp, phi); \\ no twist + \\ End of initializations + + ? mspadicL(mu,0) \\ L_p(chi^0) + %5 = 5 + 2*5^2 + 2*5^3 + 2*5^4 + ... + ? mspadicL(mu,1) \\ L_p(chi), zero for parity reasons + %6 = [O(5^13)]~ + ? mspadicL(mu,2) \\ L_p(chi^2) + %7 = 3 + 4*5 + 4*5^2 + 3*5^5 + ... + ? mspadicL(mu,[0,2]) \\ L_p(tau^2) + %8 = 3 + 5 + 2*5^2 + 2*5^3 + ... + ? mspadicL(mu, [1,0]) \\ L_p() + %9 = 3*5 + 2*5^2 + 5^3 + 2*5^7 + 5^8 + 5^10 + 2*5^11 + O(5^13) + ? mspadicL(mu,0,1) \\ L_p'(chi^0) + %10 = 2*5 + 4*5^2 + 3*5^3 + ... + ? mspadicL(mu, 2, 1) \\ L_p'(chi^2) + %11 = 4*5 + 3*5^2 + 5^3 + 5^4 + ... + @eprog + + Now several quadratic twists: \tet{mstooms} is indicated. + \bprog + ? PHI = mstooms(Mp,phi); + ? mu = mspadicmoments(Mp, PHI, 12); \\ twist by 12 + ? mspadicL(mu) + %14 = 5 + 5^2 + 5^3 + 2*5^4 + ... + ? mu = mspadicmoments(Mp, PHI, 8); \\ twist by 8 + ? mspadicL(mu) + %16 = 2 + 3*5 + 3*5^2 + 2*5^4 + ... + ? mu = mspadicmoments(Mp, PHI, -3); \\ twist by -3 < 0 + ? mspadicL(mu) + %18 = O(5^13) \\ always 0, phi is in the + part and D < 0 + @eprog + + One can locate interesting symbols of level $N$ and weight $k$ with + \kbd{msnew} and \kbd{mssplit}. Note that instead of a symbol, one can + input a 1-dimensional Hecke-subspace from \kbd{mssplit}: the function will + automatically use the underlying basis vector. + \bprog + ? M=msinit(5,4,1); \\ M_4(Gamma_0(5))^+ + ? L = mssplit(M, msnew(M)); \\ list of irreducible Hecke-subspaces + ? phi = L[1]; \\ one Galois orbit of newforms + ? #phi[1] \\... this one is rational + %4 = 1 + ? Mp = mspadicinit(M, 3, 4); + ? mu = mspadicmoments(Mp, phi); + ? mspadicL(mu) + %7 = 1 + 3 + 3^3 + 3^4 + 2*3^5 + 3^6 + O(3^9) + + ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ + ? Mp = mspadicinit(M, 3, 4); + ? L = mssplit(M, msnew(M)); + ? phi = L[1]; #phi[1] \\ ... this one is two-dimensional + %11 = 2 + ? mu = mspadicmoments(Mp, phi); + *** at top-level: mu=mspadicmoments(Mp,ph + *** ^-------------------- + *** mspadicmoments: incorrect type in mstooms [dim_Q (eigenspace) > 1] + @eprog + +Function: mspadicinit +Class: basic +Section: modular_symbols +C-Name: mspadicinit +Prototype: GLLD-1,L, +Help: mspadicinit(M,p,n,{flag}): M being a full modular symbol space, + as given by msinit and a prime p, initialize + technical data needed to compute with overconvergent modular symbols + (modulo p^n). If flag is unset, allow all symbols; if flag = 0, restrict + to ordinary symbols; else initialize for symbols phi such that + Tp(phi) = a_p * phi, with v_p(a_p) >= flag. +Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, and $p$ + a prime, initialize technical data needed to compute with overconvergent + modular symbols, modulo $p^{n}$. If $\fl$ is unset, allow + all symbols; else initialize only for a restricted range of symbols + depending on $\fl$: if $\fl = 0$ restrict to ordinary symbols, else + restrict to symbols $\phi$ such that $T_{p}(\phi) = a_{p} \phi$, + with $v_{p}(a_{p}) \geq \fl$, which is faster as $\fl$ increases. + (The fastest initialization is obtained for $\fl = 0$ where we only allow + ordinary symbols.) For supersingular eigensymbols, such that $p\mid a_{p}$, we + must further assume that $p$ does not divide the level. + \bprog + ? E = ellinit("11a1"); + ? [M,phi] = msfromell(E,1); + ? ellap(E,3) + %3 = -1 + ? Mp = mspadicinit(M, 3, 10, 0); \\ commit to ordinary symbols + ? PHI = mstooms(Mp,phi); + @eprog + + If we restrict the range of allowed symbols with \fl (for faster + initialization), exceptions will occur if $v_{p}(a_{p})$ violates this bound: + \bprog + ? E = ellinit("15a1"); + ? [M,phi] = msfromell(E,1); + ? ellap(E,7) + %3 = 0 + ? Mp = mspadicinit(M,7,5,0); \\ restrict to ordinary symbols + ? PHI = mstooms(Mp,phi) + *** at top-level: PHI=mstooms(Mp,phi) + *** ^--------------- + *** mstooms: incorrect type in mstooms [v_p(ap) > mspadicinit flag] (t_VEC). + ? Mp = mspadicinit(M,7,5); \\ no restriction + ? PHI = mstooms(Mp,phi); + @eprog\noindent This function uses $O(N^{2}(n+k)^{2}p)$ memory, + where $N$ is the level of $M$. + +Function: mspadicmoments +Class: basic +Section: modular_symbols +C-Name: mspadicmoments +Prototype: GGD1,L, +Help: mspadicmoments(Mp,PHI,{D=1}): given Mp from mspadicinit, an + overconvergent eigensymbol PHI, and optionally a fundamental discriminant + D coprime to p, return the moments of the p-1 distributions + PHI^D([0]-[oo]) | (a + pZp), 0 < a < p. To be used by mspadicL and + mspadicseries. +Doc: given \kbd{Mp} from \kbd{mspadicinit}, an overconvergent + eigensymbol \kbd{PHI} from \kbd{mstooms} and a fundamental discriminant + $D$ coprime to $p$, + let $\kbd{PHI}^{D}$ denote the twisted symbol. This function computes + the distribution $\mu = \kbd{PHI}^{D}([0] - \infty]) \mid \Z_{p}^{*}$ + restricted + to $\Z_{p}^{*}$. More precisely, it returns + the moments of the $p-1$ distributions $\kbd{PHI}^{D}([0]-[\infty]) + \mid (a + p\Z_{p})$, $0 < a < p$. + We also allow \kbd{PHI} to be given as a classical + symbol, which is then lifted to an overconvergent symbol by \kbd{mstooms}; + but this is wasteful if more than one twist is later needed. + + The returned data $\mu$ ($p$-adic distributions attached to \kbd{PHI}) + can then be used in \tet{mspadicL} or \tet{mspadicseries}. + This precomputation allows to quickly compute derivatives of different + orders or values at different characters. + \bprog + ? M = msinit(3,6, 1); + ? phi = [5,-3,-1]~; + ? msissymbol(M, phi) + %3 = 1 + ? p = 5; mshecke(M,p) * phi \\ eigenvector of T_5, a_5 = 6 + %4 = [30, -18, -6]~ + ? Mp = mspadicinit(M, p, 10, 0); \\ restrict to ordinary symbols, mod p^10 + ? PHI = mstooms(Mp, phi); + ? mu = mspadicmoments(Mp, PHI); + ? mspadicL(mu) + %8 = 5 + 2*5^2 + 2*5^3 + ... + ? mu = mspadicmoments(Mp, PHI, 12); \\ twist by 12 + ? mspadicL(mu) + %10 = 5 + 5^2 + 5^3 + 2*5^4 + ... + @eprog + +Function: mspadicseries +Class: basic +Section: modular_symbols +C-Name: mspadicseries +Prototype: GD0,L, +Help: mspadicseries(mu,{i=0}): given mu from mspadicmoments, + returns the attached p-adic series with maximal p-adic precision, depending + on the precision of M (i-th Teichmueller component, if present). +Doc: Let $\Phi$ be the $p$-adic distribution-valued overconvergent symbol + attached to a modular symbol $\phi$ for $\Gamma_{0}(N)$ (eigenvector for + $T_{N}(p)$ for the eigenvalue $a_{p}$). + If $\mu$ is the distribution on $\Z_{p}^{*}$ defined by the restriction of + $\Phi([\infty]-[0])$ to $\Z_{p}^{*}$, let + $$\hat{L}_{p}(\mu,\tau^{i})(x) + = \int_{\Z_{p}^{*}} \tau^{i}(t) (1+x)^{\log_{p}(t)/\log_{p}(u)}d\mu(t)$$ + Here, $\tau$ is the Teichm\"uller character and $u$ is a specific + multiplicative generator of $1+2p\Z_{p}$, namely $1+p$ if $p>2$ or $5$ + if $p=2$. To explain + the formula, let $G_{\infty} := \text{Gal}(\Q(\mu_{p^{\infty}})/ \Q)$, + let $\chi:G_{\infty}\to \Z_{p}^{*}$ be the cyclotomic character (isomorphism) + and $\gamma$ the element of $G_{\infty}$ such that $\chi(\gamma)=u$; + then + $\chi(\gamma)^{\log_{p}(t)/\log_{p}(u)}= \langle t \rangle$. + + The $p$-padic precision of individual terms is maximal given the precision of + the overconvergent symbol $\mu$. + \bprog + ? [M,phi] = msfromell(ellinit("17a1"),1); + ? Mp = mspadicinit(M, 5,7); + ? mu = mspadicmoments(Mp, phi,1); \\ overconvergent symbol + ? mspadicseries(mu) + %4 = (4 + 3*5 + 4*5^2 + 2*5^3 + 2*5^4 + 5^5 + 4*5^6 + 3*5^7 + O(5^9)) \ + + (3 + 3*5 + 5^2 + 5^3 + 2*5^4 + 5^6 + O(5^7))*x \ + + (2 + 3*5 + 5^2 + 4*5^3 + 2*5^4 + O(5^5))*x^2 \ + + (3 + 4*5 + 4*5^2 + O(5^3))*x^3 \ + + (3 + O(5))*x^4 + O(x^5) + @eprog\noindent + An example with nonzero Teichm\"uller: + \bprog + ? [M,phi] = msfromell(ellinit("11a1"),1); + ? Mp = mspadicinit(M, 3,10); + ? mu = mspadicmoments(Mp, phi,1); + ? mspadicseries(mu, 2) + %4 = (2 + 3 + 3^2 + 2*3^3 + 2*3^5 + 3^6 + 3^7 + 3^10 + 3^11 + O(3^12)) \ + + (1 + 3 + 2*3^2 + 3^3 + 3^5 + 2*3^6 + 2*3^8 + O(3^9))*x \ + + (1 + 2*3 + 3^4 + 2*3^5 + O(3^6))*x^2 \ + + (3 + O(3^2))*x^3 + O(x^4) + @eprog\noindent + Supersingular example (not checked) + \bprog + ? E = ellinit("17a1"); ellap(E,3) + %1 = 0 + ? [M,phi] = msfromell(E,1); + ? Mp = mspadicinit(M, 3,7); + ? mu = mspadicmoments(Mp, phi,1); + ? mspadicseries(mu) + %5 = [(2*3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + 3^5 + 3^6 + O(3^7)) \ + + (2 + 3^3 + O(3^5))*x \ + + (1 + 2*3 + O(3^2))*x^2 + O(x^3),\ + (3^-1 + 1 + 3 + 3^2 + 3^3 + 3^4 + 3^5 + 3^6 + O(3^7)) \ + + (1 + 2*3 + 2*3^2 + 3^3 + 2*3^4 + O(3^5))*x \ + + (3^-2 + 3^-1 + O(3^2))*x^2 + O(3^-2)*x^3 + O(x^4)] + @eprog\noindent + Example with a twist: + \bprog + ? E = ellinit("11a1"); + ? [M,phi] = msfromell(E,1); + ? Mp = mspadicinit(M, 3,10); + ? mu = mspadicmoments(Mp, phi,5); \\ twist by 5 + ? L = mspadicseries(mu) + %5 = (2*3^2 + 2*3^4 + 3^5 + 3^6 + 2*3^7 + 2*3^10 + O(3^12)) \ + + (2*3^2 + 2*3^6 + 3^7 + 3^8 + O(3^9))*x \ + + (3^3 + O(3^6))*x^2 + O(3^2)*x^3 + O(x^4) + ? mspadicL(mu) + %6 = [2*3^2 + 2*3^4 + 3^5 + 3^6 + 2*3^7 + 2*3^10 + O(3^12)]~ + ? ellpadicL(E,3,10,,5) + %7 = 2 + 2*3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^6 + 2*3^7 + O(3^10) + ? mspadicseries(mu,1) \\ must be 0 + %8 = O(3^12) + O(3^9)*x + O(3^6)*x^2 + O(3^2)*x^3 + O(x^4) + @eprog + +Function: mspathgens +Class: basic +Section: modular_symbols +C-Name: mspathgens +Prototype: G +Help: mspathgens(M): M being a full modular symbol space, as given by + msinit, return a set of Z[G]-generators for Div^0(P^1 Q). The output + is [g,R], where g is a minimal system of generators and R the vector of + Z[G]-relations between the given generators. +Doc: Let $\Delta_{0}:=\text{Div}^{0}(\P^{1}(\Q))$. + Let $M$ being a full modular symbol space, as given by \kbd{msinit}, + return a set of $\Z[G]$-generators for $\Delta_{0}$. The output + is $[g,R]$, where $g$ is a minimal system of generators and $R$ + the vector of $\Z[G]$-relations between the given generators. A + relation is coded by a vector of pairs $[a_{i},i]$ with $a_{i}\in \Z[G]$ + and $i$ the index of a generator, so that $\sum_{i} a_{i} g[i] = 0$. + + An element $[v]-[u]$ in $\Delta_{0}$ is coded by the ``path'' $[u,v]$, + where \kbd{oo} denotes the point at infinity $(1:0)$ on the projective + line. + An element of $\Z[G]$ is either an integer $n$ ($= n [\text{id}_{2}]$) or a + ``factorization matrix'': the first column contains distinct elements $g_{i}$ + of $G$ and the second integers $n_{i}$ and the matrix codes + $\sum_{i} n_{i} [g_{i}]$: + \bprog + ? M = msinit(11,8); \\ M_8(Gamma_0(11)) + ? [g,R] = mspathgens(M); + ? g + %3 = [[+oo, 0], [0, 1/3], [1/3, 1/2]] \\ 3 paths + ? #R \\ a single relation + %4 = 1 + ? r = R[1]; #r \\ ...involving all 3 generators + %5 = 3 + ? r[1] + %6 = [[1, 1; [1, 1; 0, 1], -1], 1] + ? r[2] + %7 = [[1, 1; [7, -2; 11, -3], -1], 2] + ? r[3] + %8 = [[1, 1; [8, -3; 11, -4], -1], 3] + @eprog\noindent + The given relation is of the form $\sum_{i} (1-\gamma_{i}) g_{i} = 0$, with + $\gamma_{i}\in \Gamma_{0}(11)$. There will always be a single relation + involving + all generators (corresponding to a round trip along all cusps), then + relations involving a single generator (corresponding to $2$ and $3$-torsion + elements in the group: + \bprog + ? M = msinit(2,8); \\ M_8(Gamma_0(2)) + ? [g,R] = mspathgens(M); + ? g + %3 = [[+oo, 0], [0, 1]] + @eprog\noindent + Note that the output depends only on the group $G$, not on the + representation $V$. + +Function: mspathlog +Class: basic +Section: modular_symbols +C-Name: mspathlog +Prototype: GG +Help: mspathlog(M,p): M being a full modular symbol space, as given by + msinit and p being a path between two elements in P^1(Q), return (p_i) + in Z[G] such that p = \sum p_i g_i, and the g_i are fixed Z[G]-generators + for Div^0(P^1 Q), see mspathgens. +Doc: Let $\Delta_{0}:=\text{Div}^{0}(\P^{1}(\Q))$. + Let $M$ being a full modular symbol space, as given by \kbd{msinit}, + encoding fixed $\Z[G]$-generators $(g_{i})$ of $\Delta_{0}$ + (see \tet{mspathgens}). + A path $p=[a,b]$ between two elements in $\P^{1}(\Q)$ corresponds to + $[b]-[a]\in \Delta_{0}$. The path extremities $a$ and $b$ may be given as + \typ{INT}, \typ{FRAC} or $\kbd{oo} = (1:0)$. Finally, we also allow + to input a path as a $2\times 2$ integer matrix, whose first + and second column give $a$ and $b$ respectively, with the convention + $[x,y]\til = (x:y)$ in $\P^{1}(\Q)$. + + Returns $(p_{i})$ in $\Z[G]$ such that $p = \sum_{i} p_{i} g_{i}$. + \bprog + ? M = msinit(2,8); \\ M_8(Gamma_0(2)) + ? [g,R] = mspathgens(M); + ? g + %3 = [[+oo, 0], [0, 1]] + ? p = mspathlog(M, [1/2,2/3]); + ? p[1] + %5 = + [[1, 0; 2, 1] 1] + + ? p[2] + %6 = + [[1, 0; 0, 1] 1] + + [[3, -1; 4, -1] 1] + ? mspathlog(M, [1,2;2,3]) == p \\ give path via a 2x2 matrix + %7 = 1 + @eprog\noindent + Note that the output depends only on the group $G$, not on the + representation $V$. + +Function: mspetersson +Class: basic +Section: modular_symbols +C-Name: mspetersson +Prototype: GDGDG +Help: mspetersson(M,{F},{G=F}): M being a full modular symbol space, + as given by msinit, calculate the intersection product {F,G} of modular + symbols F and G on M. +Doc: $M$ being a full modular symbol space for $\Gamma = \Gamma_{0}(N)$, + as given by \kbd{msinit}, + calculate the intersection product $\{F, G\}$ of modular symbols $F$ and $G$ + on $M=\Hom_{\Gamma}(\Delta_{0}, V_{k})$ extended to an hermitian bilinear + form on $M \otimes \C$ whose radical is the Eisenstein subspace of $M$. + + Suppose that $f_{1}$ and $f_{2}$ are two parabolic forms. Let $F_{1}$ + and $F_{2}$ be the attached modular symbols + $$ F_{i}(\delta)= \int_{\delta} f_{i}(z) \cdot (z X + Y)^{k-2} \,dz$$ + and let $F^{\R}_{1}$, $F^{\R}_{2}$ be the attached real modular symbols + $$ F^{\R}_{i}(\delta)= \int_{\delta} + \Re\big(f_{i}(z) \cdot (z X + Y)^{k-2} \,dz\big) $$ + Then we have + $$ + \{ F^{\R}_{1}, F^{\R}_{2} \} = -2 (2i)^{k-2} \cdot + \Im(_{\var{Petersson}}) $$ + and + $$\{ F_{1}, \bar{F_{2}} \} = (2i)^{k-2} _{\var{Petersson}}$$ + In weight 2, the intersection product $\{F, G\}$ has integer values on the + $\Z$-structure on $M$ given by \kbd{mslattice} and defines a Riemann form on + $H^{1}_{par}(\Gamma,\R)$. + + For user convenience, we allow $F$ and $G$ to be matrices and return the + attached Gram matrix. If $F$ is omitted: treat it as the full modular space + attached to $M$; if $G$ is omitted, take it equal to $F$. + \bprog + ? M = msinit(37,2); + ? C = mscuspidal(M)[1]; + ? mspetersson(M, C) + %3 = + [ 0 -17 -8 -17] + [17 0 -8 -25] + [ 8 8 0 -17] + [17 25 17 0] + ? mspetersson(M, mslattice(M,C)) + %4 = + [0 -1 0 -1] + [1 0 0 -1] + [0 0 0 -1] + [1 1 1 0] + ? E = ellinit("33a1"); + ? [M,xpm] = msfromell(E); [xp,xm,L] = xpm; + ? mspetersson(M, mslattice(M,L)) + %7 = + [0 -3] + [3 0] + ? ellmoddegree(E) + %8 = [3, -126] + @eprog + \noindent The coefficient $3$ in the matrix is the degree of the + modular parametrization. + +Function: mspolygon +Class: basic +Section: modular_symbols +C-Name: mspolygon +Prototype: GD0,L, +Help: mspolygon(M,{flag=0}): M describes a subgroup G of finite index in + the modular group PSL2(Z), as given by msinit or a positive integer N + (encoding the group G = Gamma0(N)), or by msfarey (arbitrary subgroups). + Return an hyperbolic polygon (Farey symbol) attached to G. + Binary digits of flag mean: 1=normalized polygon, 2=also add graphical + representations. +Doc: $M$ describes a subgroup $G$ of finite index in the modular group + $\text{PSL}_{2}(\Z)$, as given by \kbd{msinit} or a positive integer $N$ + (encoding the group $G = \Gamma_{0}(N)$), or by \kbd{msfarey} (arbitrary + subgroup). Return an hyperbolic polygon (Farey symbol) attached to $G$. + More precisely: + + \item Its vertices are an ordered list in $\P^{1}(\Q)$ and contain + a representatives of all cusps. + + \item Its edges are hyperbolic arcs joining two consecutive vertices; + each edge $e$ is labelled by an integer $\mu(e) \in \{\infty,2,3\}$. + + \item Given a path $(a,b)$ between two elements of $\P^{1}(\Q)$, let + $\overline{(a,b)} = (b,a)$ be the opposite path. There is an involution $e + \to e^{*}$ on the edges. We have $\mu(e) = \infty$ if and only if $e\neq + e^{*}$; + when $\mu(e) \neq 3$, $e$ is $G$-equivalent to $\overline{e^{*}}$, i.e. there + exists $\gamma_{e} \in G$ such that $e = \gamma_{e} \overline{e^{*}}$; + if $\mu(e)=3$ + there exists $\gamma_{e} \in G$ of order $3$ such that the hyperbolic triangle + $(e, \gamma_{e} e, \gamma_{e}^{2} e)$ is invariant by $\gamma_{e}$. + In all cases, + to each edge we have attached $\gamma_{e} \in G$ of order $\mu(e)$. + + \noindent The polygon is given by a triple $[E, A, g]$ + + \item The list $E$ of its consecutive edges as matrices in $M_{2}(\Z)$. + + \item The permutation $A$ attached to the involution: if $e = E[i]$ is the + $i$-th edge, then \kbd{A[i]} is the index of $e^{*}$ in $E$. + + \item The list $g$ of pairing matrices $\gamma_{e}$. + Remark that $\gamma_{e^{*}}=\gamma_{e}^{-1}$ if $\mu(e) \neq 3$, + i.e., $g[i]^{-1} = g[A[i]]$ whenever $i\neq A[i]$ ($\mu(g[i]) = 1$) or + $\mu(g[i]) = 2$ ($g[i]^{2} = 1$). Modulo these trivial relations, + the pairing matrices form a system of independant generators of $G$. Note + that $\gamma_{e}$ is elliptic if and only if $e^{*} = e$. + + \noindent The above data yields a fundamental domain for $G$ acting + on Poincar\'e's half-plane: take the convex hull of the polygon defined by + + \item The edges in $E$ such that $e \neq e^{*}$ or $e^{*}=e$, where the pairing + matrix $\gamma_{e}$ has order $2$; + + \item The edges $(r,t)$ and $(t,s)$ where the edge $e = (r,s) \in E$ is such + that $e = e^{*}$ and $\gamma_{e}$ has order $3$ and the triangle $(r,t,s)$ + is the image of $(0,\exp(2i\pi/3), \infty)$ by some element of $PSL_{2}(\Q)$ + formed around the edge. + + Binary digits of flag mean: + + 1: return a normalized hyperbolic polygon if set, else a polygon with + unimodular edges (matrices of determinant $1$). A polygon is normalized + in the sense of compact orientable surfaces if the distance $d(a,a^{*})$ + between + an edge $a$ and its image by the involution $a^{*}$ is less than 2, with + equality if and only if $a$ is \emph{linked} with another edge $b$ + ($a$, $b$, $a^{*}$ et $b^{*}$ appear consecutively in $E$ up to cyclic + permutation). In particular, the vertices of all edges such that that + $d(a,a^{*}) \neq 1$ (distance is 0 or 2) are all equivalent to $0$ modulo + $G$. The external vertices of $a a^{*}$ such that $d(a,a^{*}) = 1$ are + also equivalent to $0$; the internal vertices $a\cap a^{*}$ (a single point), + together with $0$, form a system of representatives of the cusps of + $G\bs \P^{1}(\Q)$. This is useful to compute the homology group + $H_{1}(G,\Z)$ as it gives a symplectic basis for the intersection pairing. + In this case, the number of parabolic matrices (trace 2) in the system of + generators $G$ is $2(t-1)$, where $t$ is the number of non equivalent cusps + for $G$. This is currently only implemented for $G = \Gamma_{0}(N)$. + + 2: add graphical representations (in LaTeX form) for the hyperbolic polygon + in Poincar\'e's half-space and the involution $a\to a^{*}$ of the Farey symbol. + The corresponding character strings can be included in a LaTeX document + provided the preamble contains \kbd{\bs usepackage\obr tikz\cbr}. + + \bprog + ? [V,A,g] = mspolygon(3); + ? V + %2 = [[-1, 1; -1, 0], [1, 0; 0, 1], [0, 1; -1, 1]] + ? A + %3 = Vecsmall([2, 1, 3]) + ? g + %4 = [[-1, -1; 0, -1], [1, -1; 0, 1], [1, -1; 3, -2]] + ? [V,A,g, D1,D2] = mspolygon(11,2); \\ D1 and D2 contains pictures + ? {write("F.tex", + "\\documentclass{article}\\usepackage{tikz}\\begin{document}" + D1, "\n", D2, + "\\end{document}");} + + ? [V1,A1] = mspolygon(6,1); \\ normalized + ? V1 + %8 = [[-1, 1; -1, 0], [1, 0; 0, 1], [0, 1; -1, 3], + [1, -2; 3, -5], [-2, 1; -5, 2], [1, -1; 2, -1]] + ? A1 + %9 = Vecsmall([2, 1, 4, 3, 6, 5]) + + ? [V0,A0] = mspolygon(6); \\ not normalized V[3]^* = V[6], d(V[3],V[6]) = 3 + ? A0 + %11 = Vecsmall([2, 1, 6, 5, 4, 3]) + + ? [V,A] = mspolygon(14, 1); + ? A + %13 = Vecsmall([2, 1, 4, 3, 6, 5, 9, 10, 7, 8]) + @eprog + One can see from this last example that the (normalized) polygon has the form + $$(a_{1}, a_{1}^{*}, a_{2}, a_{2}^{*}, a_{3}, a_{3}^{*}, a_{4}, a_{5}, a_{4}^{*}, a_{5}^{*}),$$ + that $X_{0}(14)$ is of genus 1 (in general the genus is the number of blocks + of the form $aba^{*}b^{*}$), has no elliptic points ($A$ has no fixed point) + and 4 cusps (number of blocks of the form $aa^{*}$ plus 1). The vertices + of edges $a_{4}$ and $a_{5}$ all project to $0$ in $X_{0}(14)$: the paths $a_{4}$ + and $a_{5}$ project as loops in $X_{0}(14)$ and give a symplectic basis of the + homology $H_{1}(X_{0}(14),\Z)$. + \bprog + ? [V,A] = mspolygon(15); + ? apply(matdet, V) \\ all unimodular + %2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + ? [V,A] = mspolygon(15,1); + ? apply(matdet, V) \\ normalized polygon but no longer unimodular edges + %4 = [1, 1, 1, 1, 2, 2, 47, 11, 47, 11] + @eprog + +Function: msqexpansion +Class: basic +Section: modular_symbols +C-Name: msqexpansion +Prototype: GGDP +Help: msqexpansion(M,projH,{B = seriesprecision}): M being a full modular + symbol space, as given by msinit, and projH being a projector on a + Hecke-simple subspace, return the Fourier coefficients [a_n, n <= B] + of the corresponding normalized newform. If B omitted, use seriesprecision. +Doc: + $M$ being a full modular symbol space, as given by \kbd{msinit}, + and \var{projH} being a projector on a Hecke-simple subspace (as given + by \tet{mssplit}), return the Fourier coefficients $a_{n}$, $n\leq B$ of the + corresponding normalized newform. If $B$ is omitted, use + \kbd{seriesprecision}. + + This function uses a naive $O(B^{2} d^{3})$ + algorithm, where $d = O(kN)$ is the dimension of $M_{k}(\Gamma_{0}(N))$. + \bprog + ? M = msinit(11,2, 1); \\ M_2(Gamma_0(11))^+ + ? L = mssplit(M, msnew(M)); + ? msqexpansion(M,L[1], 20) + %3 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1, -4, -2, 4, 0, 2] + ? ellan(ellinit("11a1"), 20) + %4 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2, 1, -2, 4, 4, -1, -4, -2, 4, 0, 2] + @eprog\noindent The shortcut \kbd{msqexpansion(M, s, B)} is available for + a symbol $s$, provided it is a Hecke eigenvector: + \bprog + ? E = ellinit("11a1"); + ? [M,S] = msfromell(E); [sp,sm] = S; + ? msqexpansion(M,sp,10) \\ in the + eigenspace + %3 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] + ? msqexpansion(M,sm,10) \\ in the - eigenspace + %4 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] + ? ellan(E, 10) + %5 = [1, -2, -1, 2, 1, 2, -2, 0, -2, -2] + @eprog + +Function: mssplit +Class: basic +Section: modular_symbols +C-Name: mssplit +Prototype: GDGD0,L, +Help: mssplit(M,{H},{dimlim}): M being a full modular symbol space, as given by + msinit, and H being a subspace (the new subspace if omitted), split H into + Hecke-simple subspaces. If dimlim is present and positive, restrict to + dim <= dimlim. +Doc: + Let $M$ denote a full modular symbol space, as given by \kbd{msinit}$(N,k,1)$ + or $\kbd{msinit}(N,k,-1)$ and let $H$ be a Hecke-stable subspace of + \kbd{msnew}$(M)$ (the full new subspace if $H$ is omitted). This function + splits $H$ into Hecke-simple subspaces. If \kbd{dimlim} is present and + positive, restrict to subspaces of dimension $\leq \kbd{dimlim}$. A subspace + is given by a structure allowing quick projection and restriction of linear + operators; its first component is a matrix with integer coefficients whose + columns form a $\Q$-basis of the subspace. + + \bprog + ? M = msinit(11,8, 1); \\ M_8(Gamma_0(11))^+ + ? L = mssplit(M); \\ split msnew(M) + ? #L + %3 = 2 + ? f = msqexpansion(M,L[1],5); f[1].mod + %4 = x^2 + 8*x - 44 + ? lift(f) + %5 = [1, x, -6*x - 27, -8*x - 84, 20*x - 155] + ? g = msqexpansion(M,L[2],5); g[1].mod + %6 = x^4 - 558*x^2 + 140*x + 51744 + @eprog\noindent To a Hecke-simple subspace corresponds an orbit of + (normalized) newforms, defined over a number field. In the above example, + we printed the polynomials defining the said fields, as well as the first + 5 Fourier coefficients (at the infinite cusp) of one such form. + +Function: msstar +Class: basic +Section: modular_symbols +C-Name: msstar +Prototype: GDG +Help: msstar(M,{H}): M being a full modular symbol space, + as given by msinit, return the matrix of the * involution, induced by + complex conjugation, acting on the (stable) subspace H (M if omitted). +Doc: $M$ being a full modular symbol space, as given by \kbd{msinit}, + return the matrix of the \kbd{*} involution, induced by complex conjugation, + acting on the (stable) subspace $H$ ($M$ if omitted). + \bprog + ? M = msinit(11,2); \\ M_2(Gamma_0(11)) + ? w = msstar(M); + ? w^2 == 1 + %3 = 1 + @eprog + +Function: mstooms +Class: basic +Section: modular_symbols +C-Name: mstooms +Prototype: GG +Help: mstooms(Mp,phi): given Mp from mspadicinit, lift the + (classical) eigen symbol phi to a distribution-valued overconvergent symbol + in the sense of Pollack and Stevens. + The resulting overconvergent eigensymbol can then be used in + mspadicmoments, then mspadicL or mspadicseries. +Doc: given \kbd{Mp} from \kbd{mspadicinit}, lift the (classical) eigen symbol + \kbd{phi} to a $p$-adic distribution-valued overconvergent symbol in the + sense of Pollack and Stevens. More precisely, let $\phi$ belong to the space + $W$ of modular symbols of level $N$, $v_{p}(N) \leq 1$, and weight $k$ which is + an eigenvector for the Hecke operator $T_{N}(p)$ for a nonzero eigenvalue + $a_{p}$ and let $N_{0} = \text{lcm}(N,p)$. + + Under the action of $T_{N_{0}}(p)$, $\phi$ generates a subspace $W_{\phi}$ of + dimension $1$ (if $p\mid N$) or $2$ (if $p$ does not divide $N$) in the + space of modular symbols of level $N_{0}$. + + Let $V_{p}=[p,0;0,1]$ and $C_{p}=[a_{p},p^{k-1};-1,0]$. + When $p$ does not divide $N$ and $a_{p}$ is divisible by $p$, \kbd{mstooms} + returns the lift $\Phi$ of $(\phi,\phi|_{k} V_{p})$ such that + $$T_{N_{0}}(p) \Phi = C_{p} \Phi$$ + + When $p$ does not divide $N$ and $a_{p}$ is not divisible by $p$, \kbd{mstooms} + returns the lift $\Phi$ of $\phi - \alpha^{-1} \phi|_{k} V_{p}$ + which is an eigenvector of $T_{N_{0}}(p)$ for the unit eigenvalue + where $\alpha^{2} - a_{p} \alpha + p^{k-1}=0$. + + The resulting overconvergent eigensymbol can then be used in + \tet{mspadicmoments}, then \tet{mspadicL} or \tet{mspadicseries}. + \bprog + ? M = msinit(3,6, 1); p = 5; + ? Tp = mshecke(M, p); factor(charpoly(Tp)) + %2 = + [x - 3126 2] + + [ x - 6 1] + ? phi = matker(Tp - 6)[,1] \\ generator of p-Eigenspace, a_p = 6 + %3 = [5, -3, -1]~ + ? Mp = mspadicinit(M, p, 10, 0); \\ restrict to ordinary symbols, mod p^10 + ? PHI = mstooms(Mp, phi); + ? mu = mspadicmoments(Mp, PHI); + ? mspadicL(mu) + %7 = 5 + 2*5^2 + 2*5^3 + ... + @eprog + A non ordinary symbol. + \bprog + ? M = msinit(4,6,1); p = 3; + ? Tp = mshecke(M, p); factor(charpoly(Tp)) + %2 = + [x - 244 3] + + [ x + 12 1] + ? phi = matker(Tp + 12)[,1] \\ a_p = -12 is divisible by p = 3 + %3 = [-1/32, -1/4, -1/32, 1]~ + ? msissymbol(M,phi) + %4 = 1 + ? Mp = mspadicinit(M,3,5,0); + ? PHI = mstooms(Mp,phi); + *** at top-level: PHI=mstooms(Mp,phi) + *** ^--------------- + *** mstooms: incorrect type in mstooms [v_p(ap) > mspadicinit flag] (t_VEC). + ? Mp = mspadicinit(M,3,5,1); + ? PHI = mstooms(Mp,phi); + @eprog + +Function: my +Class: basic +Section: programming/specific +Help: my(x,...,z): declare x,...,z as lexically-scoped local variables. + +Function: newtonpoly +Class: basic +Section: number_fields +C-Name: newtonpoly +Prototype: GG +Help: newtonpoly(x,p): Newton polygon of polynomial x with respect to the + prime p. +Doc: gives the vector of the slopes of the Newton + polygon of the polynomial $x$ with respect to the prime number $p$. The $n$ + components of the vector are in decreasing order, where $n$ is equal to the + degree of $x$. Vertical slopes occur iff the constant coefficient of $x$ is + zero and are denoted by \kbd{+oo}. + +Function: next +Class: basic +Section: programming/control +C-Name: next0 +Prototype: D1,L, +Help: next({n=1}): interrupt execution of current instruction sequence, and + start another iteration from the n-th innermost enclosing loops. +Doc: interrupts execution of current $seq$, + resume the next iteration of the innermost enclosing loop, within the + current function call (or top level loop). If $n$ is specified, resume at + the $n$-th enclosing loop. If $n$ is bigger than the number of enclosing + loops, all enclosing loops are exited. + +Function: nextprime +Class: basic +Section: number_theoretical +C-Name: nextprime +Prototype: G +Help: nextprime(x): smallest pseudoprime >= x. +Description: + (gen):int nextprime($1) +Doc: finds the smallest pseudoprime (see + \tet{ispseudoprime}) greater than or equal to $x$. $x$ can be of any real + type. Note that if $x$ is a pseudoprime, this function returns $x$ and not + the smallest pseudoprime strictly larger than $x$. To rigorously prove that + the result is prime, use \kbd{isprime}. + \bprog + ? nextprime(2) + %1 = 2 + ? nextprime(Pi) + %2 = 5 + ? nextprime(-10) + %3 = 2 \\ primes are positive + @eprog\noindent + Despite the name, please note that the function is not guaranteed to return + a prime number, although no counter-example is known at present. The return + value \emph{is} a guaranteed prime if $x \leq 2^{64}$. To rigorously prove + that the result is prime in all cases, use \kbd{isprime}. + +Function: nfalgtobasis +Class: basic +Section: number_fields +C-Name: algtobasis +Prototype: GG +Help: nfalgtobasis(nf,x): transforms the algebraic number x into a column + vector on the integral basis nf.zk. +Doc: Given an algebraic number $x$ in the number field $\var{nf}$, + transforms it to a column vector on the integral basis \kbd{\var{nf}.zk}. + \bprog + ? nf = nfinit(y^2 + 4); + ? nf.zk + %2 = [1, 1/2*y] + ? nfalgtobasis(nf, [1,1]~) + %3 = [1, 1]~ + ? nfalgtobasis(nf, y) + %4 = [0, 2]~ + ? nfalgtobasis(nf, Mod(y, y^2+4)) + %5 = [0, 2]~ + @eprog + This is the inverse function of \kbd{nfbasistoalg}. + +Function: nfbasis +Class: basic +Section: number_fields +C-Name: nfbasis +Prototype: GD& +Help: nfbasis(T,{&dK}): integral basis of the field Q[a], where a is + a root of the polynomial T, using the round 4 algorithm. An argument + [T,listP] is possible, where listP is a list of primes or a prime bound, + to get an order which is maximal at certain primes only. If present, dK is + set to the discriminant of the returned order. +Doc: + Let $T(X)$ be an irreducible polynomial with integral coefficients. This + function returns an \idx{integral basis} of the number field defined by $T$, + that is a $\Z$-basis of its maximal order. If present, \kbd{dK} is set + to the discriminant of the returned order. The basis elements are given as + elements in $K = \Q[X]/(T)$, in Hermite normal form with respect to the + $\Q$-basis $(1,X,\dots,X^{\deg T-1})$ of $K$, lifted to $\Q[X]$. + In particular its first element is always $1$ and its $i$-th element is a + polynomial of degree $i-1$ whose leading coefficient is the inverse of an + integer: the product of those integers is the index of $\Z[X]/(T)$ in the + maximal order $\Z_{K}$: + \bprog + ? nfbasis(x^2 + 4) \\ Z[X]/(T) has index 2 in Z_K + %1 = [1, x/2] + ? nfbasis(x^2 + 4, &D) + %2 = [1, x/2] + ? D + %3 = -4 + @eprog + This function uses a modified version of the \idx{round 4} algorithm, + due to David \idx{Ford}, Sebastian \idx{Pauli} and Xavier \idx{Roblot}. + + \misctitle{Local basis, orders maximal at certain primes} + + Obtaining the maximal order is hard: it requires factoring the discriminant + $D$ of $T$. Obtaining an order which is maximal at a finite explicit set of + primes is easy, but it may then be a strict suborder of the maximal order. To + specify that we are interested in a given set of places only, we can replace + the argument $T$ by an argument $[T,\var{listP}]$, where \var{listP} encodes + the primes we are interested in: it must be a factorization matrix, a vector + of integers or a single integer. + + \item Vector: we assume that it contains distinct \emph{prime} numbers. + + \item Matrix: we assume that it is a two-column matrix of a + (partial) factorization of $D$; namely the first column contains + distinct \emph{primes} and the second one the valuation of $D$ at each of + these primes. + + \item Integer $B$: this is replaced by the vector of primes up to $B$. Note + that the function will use at least $O(B)$ time: a small value, about + $10^{5}$, should be enough for most applications. Values larger than $2^{32}$ + are not supported. + + In all these cases, the primes may or may not divide the discriminant $D$ + of $T$. The function then returns a $\Z$-basis of an order whose index is + not divisible by any of these prime numbers. The result may actually be + a global integral basis, in particular if all the prime divisors of the + \emph{field} discriminant are included, but this is not guaranteed! + Note that \kbd{nfinit} has built-in support for such a check: + \bprog + ? K = nfinit([T, listP]); + ? nfcertify(K) \\ we computed an actual maximal order + %2 = []; + @eprog\noindent The first line initializes a number field structure + incorporating \kbd{nfbasis([T, listP]} in place of a proven integral basis. + The second line certifies that the resulting structure is correct. This + allows to create an \kbd{nf} structure attached to the number field $K = + \Q[X]/(T)$, when the discriminant of $T$ cannot be factored completely, + whereas the prime divisors of $\disc K$ are known. If present, the argument + \kbd{dK} is set to the discriminant of the returned order, and is + equal to the field discriminant if and only if the order is maximal. + + Of course, if \var{listP} contains a single prime number $p$, + the function returns a local integral basis for $\Z_{p}[X]/(T)$: + \bprog + ? nfbasis(x^2+x-1001) + %1 = [1, 1/3*x - 1/3] + ? nfbasis( [x^2+x-1001, [2]] ) + %2 = [1, x] + @eprog\noindent The following function computes the index $i_{T}$ + of $\Z[X]/(T)$ in the order generated by the $\Z$-basis $B$: + \bprog + nfbasisindex(T, B) = vecprod([denominator(pollead(Q)) | Q <- B]); + @eprog\noindent In particular, $B$ is a basis of the maximal order + if and only if $\kbd{poldisc}(T) / i_{T}^{2}$ is equal to the field + discriminant. More generally, this formula gives the square of index of the + order given by $B$ in $\Z_{K}$. For instance, assume that $P$ is a vector + of prime numbers containing (at least) all prime divisors of the field + discriminant, then the following construct allows to provably compute the + field discriminant and to check whether the returned basis is actually + a basis of the maximal order + \bprog + ? B = nfbasis([T, P], &D); + ? dK = sign(D) * vecprod([p^valuation(D,p) | p<-P]); + ? dK * nfbasisindex(T, B)^2 == poldisc(T) + @eprog\noindent The variable \kbd{dK} contains the field discriminant and + the last command returns $1$ if and only if $B$ is a $\Z$-basis of the + maximal order. Of course, the \kbd{nfinit} / \kbd{nfcertify} approach is + simpler, but it is also more costly. + + \misctitle{The Buchmann-Lenstra algorithm} + + We now complicate the picture: it is in fact allowed to include + \emph{composite} numbers instead of primes + in \kbd{listP} (Vector or Matrix case), provided they are pairwise coprime. + The result may still be a correct integral basis if + the field discriminant factors completely over the actual primes in the + list; again, this is not guaranteed. Adding a composite $C$ such that $C^{2}$ + \emph{divides} $D$ may help because when we consider $C$ as a prime and run + the algorithm, two good things can happen: either we succeed in proving that + no prime dividing $C$ can divide the index (without actually needing to find + those primes), or the computation exhibits a nontrivial zero divisor, + thereby factoring $C$ and we go on with the refined factorization. (Note that + including a $C$ such that $C^{2}$ does not divide $D$ is useless.) If neither + happen, then the computed basis need not generate the maximal order. Here is + an example: + \bprog + ? B = 10^5; + ? listP = factor(poldisc(T), B); \\ primes <= B dividing D + cofactor + ? basis = nfbasis([T, listP], &D) + @eprog\noindent If the computed discriminant $D$ factors completely + over the primes less than $B$ (together with the primes contained in the + \tet{addprimes} table), then everything is certified: $D$ is the field + discriminant and \kbd{basis} generates the maximal order. + This can be tested as follows: + \bprog + F = factor(D, B); P = F[,1]; E = F[,2]; + for (i = 1, #P, + if (P[i] > B && !isprime(P[i]), warning("nf may be incorrect"))); + @eprog\noindent + This is a sufficient but not a necessary condition, hence the warning, + instead of an error. + + The function \tet{nfcertify} speeds up and automates the above process: + \bprog + ? B = 10^5; + ? nf = nfinit([T, B]); + ? nfcertify(nf) + %3 = [] \\ nf is unconditionally correct + ? [basis, disc] = [nf.zk, nf.disc]; + @eprog + +Function: nfbasistoalg +Class: basic +Section: number_fields +C-Name: basistoalg +Prototype: GG +Help: nfbasistoalg(nf,x): transforms the column vector x on the integral + basis into an algebraic number. +Doc: Given an algebraic number $x$ in the number field \var{nf}, transforms it + into \typ{POLMOD} form. + \bprog + ? nf = nfinit(y^2 + 4); + ? nf.zk + %2 = [1, 1/2*y] + ? nfbasistoalg(nf, [1,1]~) + %3 = Mod(1/2*y + 1, y^2 + 4) + ? nfbasistoalg(nf, y) + %4 = Mod(y, y^2 + 4) + ? nfbasistoalg(nf, Mod(y, y^2+4)) + %5 = Mod(y, y^2 + 4) + @eprog + This is the inverse function of \kbd{nfalgtobasis}. + +Function: nfcertify +Class: basic +Section: number_fields +C-Name: nfcertify +Prototype: G +Help: nfcertify(nf): returns a vector of composite integers used to certify + nf.zk and nf.disc unconditionally (both are correct when the output + is the empty vector). +Doc: $\var{nf}$ being as output by + \kbd{nfinit}, checks whether the integer basis is known unconditionally. + This is in particular useful when the argument to \kbd{nfinit} was of the + form $[T, \kbd{listP}]$, specifying a finite list of primes when + $p$-maximality had to be proven, or a list of coprime integers to which + Buchmann-Lenstra algorithm was to be applied. + + The function returns a vector of coprime composite integers. If this vector + is empty, then \kbd{nf.zk} and \kbd{nf.disc} are correct. Otherwise, the + result is dubious. In order to obtain a certified result, one must completely + factor each of the given integers, then \kbd{addprime} each of their prime + factors, then check whether \kbd{nfdisc(nf.pol)} is equal to \kbd{nf.disc}. + +Function: nfcompositum +Class: basic +Section: number_fields +C-Name: nfcompositum +Prototype: GGGD0,L, +Help: nfcompositum(nf,P,Q,{flag=0}): vector of all possible compositums + of the number fields defined by the polynomials P and Q; flag is + optional, whose binary digits mean 1: output for each compositum, not only + the compositum polynomial pol, but a vector [R,a,b,k] where a (resp. b) is a + root of P (resp. Q) expressed as a polynomial modulo R, and a small integer k + such that al2+k*al1 is the chosen root of R; 2: assume that the number + fields defined by P and Q are linearly disjoint. +Doc: Let \var{nf} be a number field structure attached to the field $K$ + and let \sidx{compositum} $P$ and $Q$ + be squarefree polynomials in $K[X]$ in the same variable. Outputs + the simple factors of the \'etale $K$-algebra $A = K[X, Y] / (P(X), Q(Y))$. + The factors are given by a list of polynomials $R$ in $K[X]$, attached to + the number field $K[X]/ (R)$, and sorted by increasing degree (with respect + to lexicographic ordering for factors of equal degrees). Returns an error if + one of the polynomials is not squarefree. + + Note that it is more efficient to reduce to the case where $P$ and $Q$ are + irreducible first. The routine will not perform this for you, since it may be + expensive, and the inputs are irreducible in most applications anyway. In + this case, there will be a single factor $R$ if and only if the number + fields defined by $P$ and $Q$ are linearly disjoint (their intersection is + $K$). + + The binary digits of $\fl$ mean + + 1: outputs a vector of 4-component vectors $[R,a,b,k]$, where $R$ + ranges through the list of all possible compositums as above, and $a$ + (resp. $b$) expresses the root of $P$ (resp. $Q$) as an element of + $K[X]/(R)$. Finally, $k$ is a small integer such that $b + ka = X$ modulo + $R$. + + 2: assume that $P$ and $Q$ define number fields that are linearly disjoint: + both polynomials are irreducible and the corresponding number fields + have no common subfield besides $K$. This allows to save a costly + factorization over $K$. In this case return the single simple factor + instead of a vector with one element. + + A compositum is often defined by a complicated polynomial, which it is + advisable to reduce before further work. Here is an example involving + the field $K(\zeta_{5}, 5^{1/10})$, $K=\Q(\sqrt{5})$: + \bprog + ? K = nfinit(y^2-5); + ? L = nfcompositum(K, x^5 - y, polcyclo(5), 1); \\@com list of $[R,a,b,k]$ + ? [R, a] = L[1]; \\@com pick the single factor, extract $R,a$ (ignore $b,k$) + ? lift(R) \\@com defines the compositum + %4 = x^10 + (-5/2*y + 5/2)*x^9 + (-5*y + 20)*x^8 + (-20*y + 30)*x^7 + \ + (-45/2*y + 145/2)*x^6 + (-71/2*y + 121/2)*x^5 + (-20*y + 60)*x^4 + \ + (-25*y + 5)*x^3 + 45*x^2 + (-5*y + 15)*x + (-2*y + 6) + ? a^5 - y \\@com a fifth root of $y$ + %5 = 0 + ? [T, X] = rnfpolredbest(K, R, 1); + ? lift(T) \\@com simpler defining polynomial for $K[x]/(R)$ + %7 = x^10 + (-11/2*y + 25/2) + ? liftall(X) \\ @com root of $R$ in $K[x]/(T(x))$ + %8 = (3/4*y + 7/4)*x^7 + (-1/2*y - 1)*x^5 + 1/2*x^2 + (1/4*y - 1/4) + ? a = subst(a.pol, 'x, X); \\@com \kbd{a} in the new coordinates + ? liftall(a) + %10 = (-3/4*y - 7/4)*x^7 - 1/2*x^2 + ? a^5 - y + %11 = 0 + @eprog + + The main variables of $P$ and $Q$ must be the same and have higher priority + than that of \var{nf} (see~\kbd{varhigher} and~\kbd{varlower}). + +Function: nfdetint +Class: basic +Section: number_fields +C-Name: nfdetint +Prototype: GG +Help: nfdetint(nf,x): multiple of the ideal determinant of the pseudo + generating set x. +Doc: given a pseudo-matrix $x$, computes a + nonzero ideal contained in (i.e.~multiple of) the determinant of $x$. This + is particularly useful in conjunction with \kbd{nfhnfmod}. + +Function: nfdisc +Class: basic +Section: number_fields +C-Name: nfdisc +Prototype: G +Help: nfdisc(T): discriminant of the number field defined by + the polynomial T. An argument [T,listP] is possible, where listP is a list + of primes or a prime bound. +Doc: \idx{field discriminant} of the number field defined by the integral, + preferably monic, irreducible polynomial $T(X)$. Returns the discriminant of + the number field $\Q[X]/(T)$, using the Round $4$ algorithm. + + \misctitle{Local discriminants, valuations at certain primes} + + As in \kbd{nfbasis}, the argument $T$ can be replaced by $[T,\var{listP}]$, + where \kbd{listP} is as in \kbd{nfbasis}: a vector of pairwise coprime + integers (usually distinct primes), a factorization matrix, or a single + integer. In that case, the function returns the discriminant of an order + whose basis is given by \kbd{nfbasis(T,listP)}, which need not be the maximal + order, and whose valuation at a prime entry in \kbd{listP} is the same as the + valuation of the field discriminant. + + In particular, if \kbd{listP} is $[p]$ for a prime $p$, we can + return the $p$-adic discriminant of the maximal order of $\Z_{p}[X]/(T)$, + as a power of $p$, as follows: + \bprog + ? padicdisc(T,p) = p^valuation(nfdisc([T,[p]]), p); + ? nfdisc(x^2 + 6) + %2 = -24 + ? padicdisc(x^2 + 6, 2) + %3 = 8 + ? padicdisc(x^2 + 6, 3) + %4 = 3 + @eprog\noindent The following function computes the discriminant of the + maximal order under the assumption that $P$ is a vector of prime numbers + containing (at least) all prime divisors of the field discriminant: + \bprog + globaldisc(T, P) = + { my (D = nfdisc([T, P])); + sign(D) * vecprod([p^valuation(D,p) | p <-P]); + } + ? globaldisc(x^2 + 6, [2, 3, 5]) + %1 = -24 + @eprog + + \synt{nfdisc}{GEN T}. Also available is \fun{GEN}{nfbasis}{GEN T, GEN *d}, + which returns the order basis, and where \kbd{*d} receives the order + discriminant. + +Function: nfdiscfactors +Class: basic +Section: number_fields +C-Name: nfdiscfactors +Prototype: G +Help: nfdiscfactors(T): [D, faD], where D = nfdisc(T), and faD is the + factorization of |D|. +Doc: given a polynomial $T$ with integer coefficients, return + $[D, \var{faD}]$ where $D$ is \kbd{nfdisc}$(T)$ and + \var{faD} is the factorization of $|D|$. All the variants \kbd{[T,listP]} + are allowed (see \kbd{??nfdisc}), in which case \var{faD} is the + factorization of the discriminant underlying order (which need not be maximal + at the primes not specified by \kbd{listP}) and the factorization may + contain large composites. + \bprog + ? T = x^3 - 6021021*x^2 + 12072210077769*x - 8092423140177664432; + ? [D,faD] = nfdiscfactors(T); print(faD); D + [3, 3; 500009, 2] + %2 = -6750243002187] + + ? T = x^3 + 9*x^2 + 27*x - 125014250689643346789780229390526092263790263725; + ? [D,faD] = nfdiscfactors(T); print(faD); D + [3, 3; 1000003, 2] + %4 = -27000162000243 + + ? [D,faD] = nfdiscfactors([T, 10^3]); print(faD) + [3, 3; 125007125141751093502187, 2] + @eprog\noindent In the final example, we only get a partial factorization, + which is only guaranteed correct at primes $\leq 10^{3}$. + + The function also accept number field structures, for instance as output by + \kbd{nfinit}, and returns the field discriminant and its factorization: + \bprog + ? T = x^3 + 9*x^2 + 27*x - 125014250689643346789780229390526092263790263725; + ? nf = nfinit(T); [D,faD] = nfdiscfactors(T); print(faD); D + %2 = -27000162000243 + ? nf.disc + %3 = -27000162000243 + @eprog + +Function: nfeltadd +Class: basic +Section: number_fields +C-Name: nfadd +Prototype: GGG +Help: nfeltadd(nf,x,y): element x+y in nf. +Doc: + given two elements $x$ and $y$ in + \var{nf}, computes their sum $x+y$ in the number field $\var{nf}$. + + \bprog + ? nf = nfinit(1+x^2); + ? nfeltadd(nf, 1, x) \\ 1 + I + %2 = [1, 1]~ + @eprog + +Function: nfeltdiv +Class: basic +Section: number_fields +C-Name: nfdiv +Prototype: GGG +Help: nfeltdiv(nf,x,y): element x/y in nf. +Doc: given two elements $x$ and $y$ in + \var{nf}, computes their quotient $x/y$ in the number field $\var{nf}$. + +Function: nfeltdiveuc +Class: basic +Section: number_fields +C-Name: nfdiveuc +Prototype: GGG +Help: nfeltdiveuc(nf,x,y): gives algebraic integer q such that x-qy is small. +Doc: given two elements $x$ and $y$ in + \var{nf}, computes an algebraic integer $q$ in the number field $\var{nf}$ + such that the components of $x-qy$ are reasonably small. In fact, this is + functionally identical to \kbd{round(nfdiv(\var{nf},x,y))}. + +Function: nfeltdivmodpr +Class: basic +Section: number_fields +C-Name: nfdivmodpr +Prototype: GGGG +Obsolete: 2016-08-09 +Help: nfeltdivmodpr(nf,x,y,pr): this function is obsolete, use nfmodpr. +Doc: this function is obsolete, use \kbd{nfmodpr}. + + Given two elements $x$ + and $y$ in \var{nf} and \var{pr} a prime ideal in \kbd{modpr} format (see + \tet{nfmodprinit}), computes their quotient $x / y$ modulo the prime ideal + \var{pr}. +Variant: This function is normally useless in library mode. Project your + inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. + +Function: nfeltdivrem +Class: basic +Section: number_fields +C-Name: nfdivrem +Prototype: GGG +Help: nfeltdivrem(nf,x,y): gives [q,r] such that r=x-qy is small. +Doc: given two elements $x$ and $y$ in + \var{nf}, gives a two-element row vector $[q,r]$ such that $x=qy+r$, $q$ is + an algebraic integer in $\var{nf}$, and the components of $r$ are + reasonably small. + +Function: nfeltembed +Class: basic +Section: number_fields +C-Name: nfeltembed +Prototype: GGDGp +Help: nfeltembed(nf,x,{pl}): complex embeddings of x at places given + by vector pl. +Doc: given an element $x$ in the number field \var{nf}, return + the (real or) complex embeddings of $x$ specified by optional argument + \var{pl}, at the current \kbd{realprecision}: + + \item \var{pl} omitted: return the vector of embeddings at all $r_{1}+r_{2}$ + places; + + \item \var{pl} an integer between $1$ and $r_{1}+r_{2}$: return the + $i$-th embedding of $x$, attached to the $i$-th root of \kbd{nf.pol}, + i.e. \kbd{nf.roots$[i]$}; + + \item \var{pl} a vector or \typ{VECSMALL}: return the vector of embeddings; the $i$-th + entry gives the embedding at the place attached to the $\var{pl}[i]$-th real + root of \kbd{nf.pol}. + + \bprog + ? nf = nfinit('y^3 - 2); + ? nf.sign + %2 = [1, 1] + ? nfeltembed(nf, 'y) + %3 = [1.25992[...], -0.62996[...] + 1.09112[...]*I]] + ? nfeltembed(nf, 'y, 1) + %4 = 1.25992[...] + ? nfeltembed(nf, 'y, 3) \\ there are only 2 arch. places + *** at top-level: nfeltembed(nf,'y,3) + *** ^----------------- + *** nfeltembed: domain error in nfeltembed: index > 2 + @eprog + +Function: nfeltispower +Class: basic +Section: number_fields +C-Name: nfispower +Prototype: lGGLD& +Help: nfeltispower(nf,x,n,{&y}): returns 1 if x is an n-th power in nf (and set y to + an n-th root if present), else returns 0. +Doc: returns $1$ if $x$ is an $n$-th power in the number field \kbd{nf} (and sets $y$ to an $n$-th root if the + argument is present), else returns 0. + + \bprog + ? nf = nfinit(1+x^2); + ? nfeltispower(nf, -4, 4, &y) + %2 = 1 + ? y + %3 = [-1, -1]~ + @eprog + +Function: nfeltissquare +Class: basic +Section: number_fields +C-Name: nfissquare +Prototype: lGGD& +Help: nfeltissquare(nf,x,{&y}): returns 1 if x is a square in nf (and sets y to a + square root if present), else returns 0. +Doc: returns $1$ if $x$ is a square in \kbd{nf} (and sets $y$ to a square root if the + argument is present), else returns 0. + + \bprog + ? nf = nfinit(1+x^2); + ? nfeltissquare(nf, -1, &y) + %2 = 1 + ? y + %3 = [0, -1]~ + @eprog + +Function: nfeltmod +Class: basic +Section: number_fields +C-Name: nfmod +Prototype: GGG +Help: nfeltmod(nf,x,y): gives r such that r=x-qy is small with q algebraic + integer. +Doc: + given two elements $x$ and $y$ in + \var{nf}, computes an element $r$ of $\var{nf}$ of the form $r=x-qy$ with + $q$ and algebraic integer, and such that $r$ is small. This is functionally + identical to + $$\kbd{x - nfmul(\var{nf},round(nfdiv(\var{nf},x,y)),y)}.$$ + +Function: nfeltmul +Class: basic +Section: number_fields +C-Name: nfmul +Prototype: GGG +Help: nfeltmul(nf,x,y): element x.y in nf. +Doc: given two elements $x$ and $y$ in \var{nf}, computes their product $x*y$ + in the number field $\var{nf}$. + +Function: nfeltmulmodpr +Class: basic +Section: number_fields +C-Name: nfmulmodpr +Prototype: GGGG +Obsolete: 2016-08-09 +Help: nfeltmulmodpr(nf,x,y,pr): this function is obsolete, use nfmodpr. +Doc: this function is obsolete, use \kbd{nfmodpr}. + + Given two elements $x$ and + $y$ in \var{nf} and \var{pr} a prime ideal in \kbd{modpr} format (see + \tet{nfmodprinit}), computes their product $x*y$ modulo the prime ideal + \var{pr}. +Variant: This function is normally useless in library mode. Project your + inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. + +Function: nfeltnorm +Class: basic +Section: number_fields +C-Name: nfnorm +Prototype: GG +Help: nfeltnorm(nf,x): norm of x. +Doc: returns the absolute norm of $x$. + +Function: nfeltpow +Class: basic +Section: number_fields +C-Name: nfpow +Prototype: GGG +Help: nfeltpow(nf,x,k): element x^k in nf. +Doc: given an element $x$ in \var{nf}, and a positive or negative integer $k$, + computes $x^{k}$ in the number field $\var{nf}$. +Variant: \fun{GEN}{nfinv}{GEN nf, GEN x} correspond to $k = -1$, and + \fun{GEN}{nfsqr}{GEN nf,GEN x} to $k = 2$. + +Function: nfeltpowmodpr +Class: basic +Section: number_fields +C-Name: nfpowmodpr +Prototype: GGGG +Obsolete: 2016-08-09 +Help: nfeltpowmodpr(nf,x,k,pr): this function is obsolete, use nfmodpr. +Doc: this function is obsolete, use \kbd{nfmodpr}. + + Given an element $x$ in \var{nf}, an integer $k$ and a prime ideal + \var{pr} in \kbd{modpr} format + (see \tet{nfmodprinit}), computes $x^{k}$ modulo the prime ideal \var{pr}. +Variant: This function is normally useless in library mode. Project your + inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. + +Function: nfeltreduce +Class: basic +Section: number_fields +C-Name: nfreduce +Prototype: GGG +Help: nfeltreduce(nf,a,id): gives r such that a-r is in the ideal id and r + is small. +Doc: given an ideal \var{id} in + Hermite normal form and an element $a$ of the number field $\var{nf}$, + finds an element $r$ in $\var{nf}$ such that $a-r$ belongs to the ideal + and $r$ is small. + +Function: nfeltreducemodpr +Class: basic +Section: number_fields +C-Name: nfreducemodpr +Prototype: GGG +Obsolete: 2016-08-09 +Help: nfeltreducemodpr(nf,x,pr): this function is obsolete, use nfmodpr. +Doc: this function is obsolete, use \kbd{nfmodpr}. + + Given an element $x$ of the number field $\var{nf}$ and a prime ideal + \var{pr} in \kbd{modpr} format compute a canonical representative for the + class of $x$ modulo \var{pr}. +Variant: This function is normally useless in library mode. Project your + inputs to the residue field using \kbd{nf\_to\_Fq}, then work there. + +Function: nfeltsign +Class: basic +Section: number_fields +C-Name: nfeltsign +Prototype: GGDG +Help: nfeltsign(nf,x,{pl}): signs of real embeddings of x at places given + by vector pl. +Doc: given an element $x$ in the number field \var{nf}, returns the signs of + the real embeddings of $x$ specified by optional argument \var{pl}: + + \item \var{pl} omitted: return the vector of signs at all $r_{1}$ real places; + + \item \var{pl} an integer between $1$ and $r_{1}$: return the sign of the + $i$-th embedding of $x$, attached to the $i$-th real root of \kbd{nf.pol}, + i.e. \kbd{nf.roots$[i]$}; + + \item \var{pl} a vector or \typ{VECSMALL}: return the vector of signs; the $i$-th + entry gives the sign at the real place attached to the $\var{pl}[i]$-th real + root of \kbd{nf.pol}. + + \bprog + ? nf = nfinit(polsubcyclo(11,5,'y)); \\ Q(cos(2 pi/11)) + ? nf.sign + %2 = [5, 0] + ? x = Mod('y, nf.pol); + ? nfeltsign(nf, x) + %4 = [-1, -1, -1, 1, 1] + ? nfeltsign(nf, x, 1) + %5 = -1 + ? nfeltsign(nf, x, [1..4]) + %6 = [-1, -1, -1, 1] + ? nfeltsign(nf, x, 6) \\ there are only 5 real embeddings + *** at top-level: nfeltsign(nf,x,6) + *** ^----------------- + *** nfeltsign: domain error in nfeltsign: index > 5 + @eprog + +Function: nfelttrace +Class: basic +Section: number_fields +C-Name: nftrace +Prototype: GG +Help: nfelttrace(nf,x): trace of x. +Doc: returns the absolute trace of $x$. + +Function: nfeltval +Class: basic +Section: number_fields +C-Name: gpnfvalrem +Prototype: GGGD& +Help: nfeltval(nf,x,pr,{&y}): valuation of element x at the prime pr as output + by idealprimedec. +Doc: given an element $x$ in + \var{nf} and a prime ideal \var{pr} in the format output by + \kbd{idealprimedec}, computes the valuation $v$ at \var{pr} of the + element $x$. The valuation of $0$ is \kbd{+oo}. + \bprog + ? nf = nfinit(x^2 + 1); + ? P = idealprimedec(nf, 2)[1]; + ? nfeltval(nf, x+1, P) + %3 = 1 + @eprog\noindent + This particular valuation can also be obtained using + \kbd{idealval(\var{nf},x,\var{pr})}, since $x$ is then converted to a + principal ideal. + + If the $y$ argument is present, sets $y = x \tau^{v}$, where $\tau$ is a + fixed ``anti-uniformizer'' for \var{pr}: its valuation at \var{pr} is $-1$; + its valuation is $0$ at other prime ideals dividing \kbd{\var{pr}.p} and + nonnegative at all other primes. In other words $y$ is the part of $x$ + coprime to \var{pr}. If $x$ is an algebraic integer, so is $y$. + \bprog + ? nfeltval(nf, x+1, P, &y); y + %4 = [0, 1]~ + @eprog + For instance if $x = \prod_{i} x_{i}^{e_{i}}$ is known to be coprime to + \var{pr}, where the $x_{i}$ are algebraic integers and $e_{i}\in\Z$ then, + if $v_{i} = \kbd{nfeltval}(\var{nf}, x_{i}, \var{pr}, \&y_{i})$, we still + have $x = \prod_{i} y_{i}^{e_{i}}$, where the $y_{i}$ are still algebraic + integers but now all of them are coprime to \var{pr}. They can then be + mapped to the residue field of \var{pr} more efficiently than if the product + had been expanded beforehand: we can reduce mod \var{pr} after each ring + operation. +Variant: Also available are + \fun{long}{nfvalrem}{GEN nf, GEN x, GEN pr, GEN *y = NULL}, which returns + \tet{LONG_MAX} if $x = 0$ and the valuation as a \kbd{long} integer, + and \fun{long}{nfval}{GEN nf, GEN x, GEN pr}, which only returns the + valuation ($y = \kbd{NULL}$). + +Function: nffactor +Class: basic +Section: number_fields +C-Name: nffactor +Prototype: GG +Help: nffactor(nf,T): factor polynomial T in number field nf. +Doc: factorization of the univariate + polynomial (or rational function) $T$ over the number field $\var{nf}$ given + by \kbd{nfinit}; $T$ has coefficients in $\var{nf}$ (i.e.~either scalar, + polmod, polynomial or column vector). The factors are sorted by increasing + degree. + + The main variable of $\var{nf}$ must be of \emph{lower} + priority than that of $T$, see \secref{se:priority}. However if + the polynomial defining the number field occurs explicitly in the + coefficients of $T$ as modulus of a \typ{POLMOD} or as a \typ{POL} + coefficient, its main variable must be \emph{the same} as the main variable + of $T$. For example, + \bprog + ? nf = nfinit(y^2 + 1); + ? nffactor(nf, x^2 + y); \\@com OK + ? nffactor(nf, x^2 + Mod(y, y^2+1)); \\ @com OK + ? nffactor(nf, x^2 + Mod(z, z^2+1)); \\ @com WRONG + @eprog + + It is possible to input a defining polynomial for \var{nf} + instead, but this is in general less efficient since parts of an \kbd{nf} + structure will then be computed internally. This is useful in two + situations: when you do not need the \kbd{nf} elsewhere, or when you cannot + initialize an \kbd{nf} due to integer factorization difficulties when + attempting to compute the field discriminant and maximal order. In all + cases, the function runs in polynomial time using Belabas's variant + of \idx{van Hoeij}'s algorithm, which copes with hundreds of modular factors. + + \misctitle{Caveat} \kbd{nfinit([T, listP])} allows to compute in polynomial + time a conditional \var{nf} structure, which sets \kbd{nf.zk} to an order + which is not guaranteed to be maximal at all primes. Always either use + \kbd{nfcertify} first (which may not run in polynomial time) or make sure + to input \kbd{nf.pol} instead of the conditional \var{nf}: \kbd{nffactor} is + able to recover in polynomial time in this case, instead of potentially + missing a factor. + +Function: nffactorback +Class: basic +Section: number_fields +C-Name: nffactorback +Prototype: GGDG +Help: nffactorback(nf,f,{e}): given a factorization f, returns + the factored object back as an nf element. +Doc: gives back the \var{nf} element corresponding to a factorization. + The integer $1$ corresponds to the empty factorization. + + If $e$ is present, $e$ and $f$ must be vectors of the same length ($e$ being + integral), and the corresponding factorization is the product of the + $f[i]^{e[i]}$. + + If not, and $f$ is vector, it is understood as in the preceding case with $e$ + a vector of 1s: we return the product of the $f[i]$. Finally, $f$ can be a + regular factorization matrix. + \bprog + ? nf = nfinit(y^2+1); + ? nffactorback(nf, [3, y+1, [1,2]~], [1, 2, 3]) + %2 = [12, -66]~ + ? 3 * (I+1)^2 * (1+2*I)^3 + %3 = 12 - 66*I + @eprog + +Function: nffactormod +Class: basic +Section: number_fields +C-Name: nffactormod +Prototype: GGG +Obsolete: 2016-09-18 +Help: nffactormod(nf,Q,pr): this routine is obsolete, use nfmodpr and + factormod. Factor polynomial Q modulo prime ideal pr + in number field nf. +Doc: this routine is obsolete, use \kbd{nfmodpr} and \kbd{factormod}. + + Factors the univariate polynomial $Q$ modulo the prime ideal \var{pr} in + the number field $\var{nf}$. The coefficients of $Q$ belong to the number + field (scalar, polmod, polynomial, even column vector) and the main variable + of $\var{nf}$ must be of lower priority than that of $Q$ (see + \secref{se:priority}). The prime ideal \var{pr} is either in + \tet{idealprimedec} or (preferred) \tet{modprinit} format. The coefficients + of the polynomial factors are lifted to elements of \var{nf}: + \bprog + ? K = nfinit(y^2+1); + ? P = idealprimedec(K, 3)[1]; + ? nffactormod(K, x^2 + y*x + 18*y+1, P) + %3 = + [x + (2*y + 1) 1] + + [x + (2*y + 2) 1] + ? P = nfmodprinit(K, P); \\ convert to nfmodprinit format + ? nffactormod(K, x^2 + y*x + 18*y+1) + %5 = + [x + (2*y + 1) 1] + + [x + (2*y + 2) 1] + @eprog\noindent Same result, of course, here about 10\% faster due to the + precomputation. + +Function: nfgaloisapply +Class: basic +Section: number_fields +C-Name: galoisapply +Prototype: GGG +Help: nfgaloisapply(nf,aut,x): apply the Galois automorphism aut to the object + x (element or ideal) in the number field nf. +Doc: let $\var{nf}$ be a + number field as output by \kbd{nfinit}, and let \var{aut} be a \idx{Galois} + automorphism of $\var{nf}$ expressed by its image on the field generator + (such automorphisms can be found using \kbd{nfgaloisconj}). The function + computes the action of the automorphism \var{aut} on the object $x$ in the + number field; $x$ can be a number field element, or an ideal (possibly + extended). Because of possible confusion with elements and ideals, other + vector or matrix arguments are forbidden. + \bprog + ? nf = nfinit(x^2+1); + ? L = nfgaloisconj(nf) + %2 = [-x, x]~ + ? aut = L[1]; /* the nontrivial automorphism */ + ? nfgaloisapply(nf, aut, x) + %4 = Mod(-x, x^2 + 1) + ? P = idealprimedec(nf,5); /* prime ideals above 5 */ + ? nfgaloisapply(nf, aut, P[2]) == P[1] + %6 = 0 \\ !!!! + ? idealval(nf, nfgaloisapply(nf, aut, P[2]), P[1]) + %7 = 1 + @eprog\noindent The surprising failure of the equality test (\kbd{\%7}) is + due to the fact that although the corresponding prime ideals are equal, their + representations are not. (A prime ideal is specified by a uniformizer, and + there is no guarantee that applying automorphisms yields the same elements + as a direct \kbd{idealprimedec} call.) + + The automorphism can also be given as a column vector, representing the + image of \kbd{Mod(x, nf.pol)} as an algebraic number. This last + representation is more efficient and should be preferred if a given + automorphism must be used in many such calls. + \bprog + ? nf = nfinit(x^3 - 37*x^2 + 74*x - 37); + ? aut = nfgaloisconj(nf)[2]; \\ @com an automorphism in basistoalg form + %2 = -31/11*x^2 + 1109/11*x - 925/11 + ? AUT = nfalgtobasis(nf, aut); \\ @com same in algtobasis form + %3 = [16, -6, 5]~ + ? v = [1, 2, 3]~; nfgaloisapply(nf, aut, v) == nfgaloisapply(nf, AUT, v) + %4 = 1 \\ @com same result... + ? for (i=1,10^5, nfgaloisapply(nf, aut, v)) + time = 463 ms. + ? for (i=1,10^5, nfgaloisapply(nf, AUT, v)) + time = 343 ms. \\ @com but the latter is faster + @eprog + +Function: nfgaloisconj +Class: basic +Section: number_fields +C-Name: galoisconj0 +Prototype: GD0,L,DGp +Help: nfgaloisconj(nf,{flag=0},{d}): list of conjugates of a root of the + polynomial x=nf.pol in the same number field. flag is optional (set to 0 by + default), meaning 0: use combination of flag 4 and 1, always complete; 1: + use nfroots; 4: use Allombert's algorithm, complete if the field is Galois of + degree <= 35 (see manual for details). nf can be simply a polynomial. +Doc: $\var{nf}$ being a number field as output by \kbd{nfinit}, computes the + conjugates of a root $r$ of the nonconstant polynomial $x=\var{nf}[1]$ + expressed as polynomials in $r$. This also makes sense when the number field + is not \idx{Galois} since some conjugates may lie in the field. + $\var{nf}$ can simply be a polynomial. + + If no flags or $\fl=0$, use a combination of flag $4$ and $1$ and the result + is always complete. There is no point whatsoever in using the other flags. + + If $\fl=1$, use \kbd{nfroots}: a little slow, but guaranteed to work in + polynomial time. + + If $\fl=4$, use \kbd{galoisinit}: very fast, but only applies to (most) + Galois fields. If the field is Galois with weakly super-solvable Galois + group (see \tet{galoisinit}), return the complete list of automorphisms, else + only the identity element. If present, $d$ is assumed to be a multiple of the + least common denominator of the conjugates expressed as polynomial in a root + of \var{pol}. + + This routine can only compute $\Q$-automorphisms, but it may be used to get + $K$-automorphism for any base field $K$ as follows: + \bprog + rnfgaloisconj(nfK, R) = \\ K-automorphisms of L = K[X] / (R) + { + my(polabs, N,al,S, ala,k, vR); + R *= Mod(1, nfK.pol); \\ convert coeffs to polmod elts of K + vR = variable(R); + al = Mod(variable(nfK.pol),nfK.pol); + [polabs,ala,k] = rnfequation(nfK, R, 1); + Rt = if(k==0,R,subst(R,vR,vR-al*k)); + N = nfgaloisconj(polabs) % Rt; \\ Q-automorphisms of L + S = select(s->subst(Rt, vR, Mod(s,Rt)) == 0, N); + if (k==0, S, apply(s->subst(s,vR,vR+k*al)-k*al,S)); + } + K = nfinit(y^2 + 7); + rnfgaloisconj(K, x^4 - y*x^3 - 3*x^2 + y*x + 1) \\ K-automorphisms of L + @eprog +Variant: Use directly + \fun{GEN}{galoisconj}{GEN nf, GEN d}, corresponding to $\fl = 0$, the others + only have historical interest. + +Function: nfgrunwaldwang +Class: basic +Section: number_fields +C-Name: nfgrunwaldwang +Prototype: GGGGDn +Help: nfgrunwaldwang(nf,Lpr,Ld,pl,{v='x}): a polynomial in the variable v + defining a cyclic extension of nf (given in nf or bnf form) with local + behavior prescribed by Lpr, Ld and pl: the extension has local degree a + multiple of Ld[i] at the prime Lpr[i], and the extension is complex at the + i-th real place of nf if pl[i]=-1 (no condition if pl[i]=0). The extension + has degree the LCM of the local degrees. +Doc: Given \var{nf} a number field in \var{nf} or \var{bnf} format, + a \typ{VEC} \var{Lpr} of primes of \var{nf} and a \typ{VEC} \var{Ld} of + positive integers of the same length, a \typ{VECSMALL} \var{pl} of length + $r_{1}$ the number of real places of \var{nf}, computes a polynomial with + coefficients in \var{nf} defining a cyclic extension of \var{nf} of + minimal degree satisfying certain local conditions: + + \item at the prime~$Lpr[i]$, the extension has local degree a multiple + of~$Ld[i]$; + + \item at the $i$-th real place of \var{nf}, it is complex if $pl[i]=-1$ + (no condition if $pl[i]=0$). + + The extension has degree the LCM of the local degrees. Currently, the degree + is restricted to be a prime power for the search, and to be prime for the + construction because of the \kbd{rnfkummer} restrictions. + + When \var{nf} is $\Q$, prime integers are accepted instead of \kbd{prid} + structures. However, their primality is not checked and the behavior is + undefined if you provide a composite number. + + \misctitle{Warning} If the number field \var{nf} does not contain the $n$-th + roots of unity where $n$ is the degree of the extension to be computed, + the function triggers the computation of the \var{bnf} of $nf(\zeta_{n})$, + which may be costly. + + \bprog + ? nf = nfinit(y^2-5); + ? pr = idealprimedec(nf,13)[1]; + ? pol = nfgrunwaldwang(nf, [pr], [2], [0,-1], 'x) + %3 = x^2 + Mod(3/2*y + 13/2, y^2 - 5) + @eprog + +Function: nfhilbert +Class: basic +Section: number_fields +C-Name: nfhilbert0 +Prototype: lGGGDG +Help: nfhilbert(nf,a,b,{pr}): if pr is omitted, global Hilbert symbol (a,b) in + nf, that is 1 if X^2-aY^2-bZ^2 has a nontrivial solution (X,Y,Z) in nf, -1 + otherwise. Otherwise compute the local symbol modulo the prime ideal pr. +Doc: if \var{pr} is omitted, + compute the global quadratic \idx{Hilbert symbol} $(a,b)$ in $\var{nf}$, that + is $1$ if $x^{2} - a y^{2} - b z^{2}$ has a non trivial solution $(x,y,z)$ in + $\var{nf}$, and $-1$ otherwise. Otherwise compute the local symbol modulo + the prime ideal \var{pr}, as output by \kbd{idealprimedec}. +Variant: + Also available is \fun{long}{nfhilbert}{GEN nf,GEN a,GEN b} (global + quadratic Hilbert symbol), where \kbd{nf} is a true \var{nf} structure. + +Function: nfhnf +Class: basic +Section: number_fields +C-Name: nfhnf0 +Prototype: GGD0,L, +Help: nfhnf(nf,x,{flag=0}): if x=[A,I], gives a pseudo-basis [B,J] of the module + sum A_jI_j. If flag is nonzero, return [[B,J], U], where U is the + transformation matrix such that AU = [0|B]. +Doc: given a pseudo-matrix $(A,I)$, finds a + pseudo-basis $(B,J)$ in \idx{Hermite normal form} of the module it generates. + If $\fl$ is nonzero, also return the transformation matrix $U$ such that + $AU = [0|B]$. +Variant: Also available: + + \fun{GEN}{nfhnf}{GEN nf, GEN x} ($\fl = 0$). + + \fun{GEN}{rnfsimplifybasis}{GEN bnf, GEN x} simplifies the pseudo-basis + $x = (A,I)$, returning a pseudo-basis $(B,J)$. The ideals in the list $J$ + are integral, primitive and either trivial (equal to the full ring of + integer) or nonprincipal. + +Function: nfhnfmod +Class: basic +Section: number_fields +C-Name: nfhnfmod +Prototype: GGG +Help: nfhnfmod(nf,x,detx): if x=[A,I], and detx is a multiple of the ideal + determinant of x, gives a pseudo-basis of the module sum A_jI_j. +Doc: given a pseudo-matrix $(A,I)$ + and an ideal \var{detx} which is contained in (read integral multiple of) the + determinant of $(A,I)$, finds a pseudo-basis in \idx{Hermite normal form} + of the module generated by $(A,I)$. This avoids coefficient explosion. + \var{detx} can be computed using the function \kbd{nfdetint}. + +Function: nfinit +Class: basic +Section: number_fields +C-Name: nfinit0 +Prototype: GD0,L,p +Help: nfinit(pol,{flag=0}): pol being a nonconstant irreducible polynomial in + Q[X], returns an nf structure attached to the number field Q[X] / (pol). + Binary digits of flag mean + 1: two-element vector [nf,Mod(a,P)], where Mod(a,P) is a polmod equal to + Mod(x,pol) and P=nf.pol; 2: first use polredbest to find a simpler + polynomial P; 4: do not LLL-reduce the maximal order basis nf.zk. +Description: + (gen, ?0):nf:prec nfinit0($1, 0, $prec) + (gen, 1):nf:prec nfinit0($1, nf_ORIG, $prec) + (gen, 2):nf:prec nfinit0($1, nf_RED, $prec) + (gen, 3):gen:prec nfinit0($1, nf_ORIG|nf_RED, $prec) + (gen, 4):gen:prec nfinit0($1, nf_NOLLL, $prec) + (gen, #small):void $"incorrect flag in nfinit" + (gen, small):gen:prec nfinit0($1, $2, $prec) +Doc: \var{pol} being a nonconstant irreducible polynomial in $\Q[X]$, + preferably monic and integral, initializes a + \emph{number field} (or \var{nf}) structure attached to the field $K$ defined + by \var{pol}. As such, it's a technical object passed as the first argument + to most \kbd{nf}\var{xxx} functions, but it contains some information which + may be directly useful. Access to this information via \emph{member + functions} is preferred since the specific data organization given below + may change in the future. Currently, \kbd{nf} is a row vector with 9 + components: + + $\var{nf}[1]$ contains the polynomial \var{pol} (\kbd{\var{nf}.pol}). + + $\var{nf}[2]$ contains $[r1,r2]$ (\kbd{\var{nf}.sign}, \kbd{\var{nf}.r1}, + \kbd{\var{nf}.r2}), the number of real and complex places of $K$. + + $\var{nf}[3]$ contains the discriminant $d(K)$ (\kbd{\var{nf}.disc}) of $K$. + + $\var{nf}[4]$ contains the index of $\var{nf}[1]$ (\kbd{\var{nf}.index}), + i.e.~$[\Z_{K} : \Z[\theta]]$, where $\theta$ is any root of $\var{nf}[1]$. + + $\var{nf}[5]$ is a vector containing 7 matrices $M$, $G$, \var{roundG}, $T$, + \var{MD}, \var{TI}, \var{MDI} and a vector \var{vP} defined as follows: + + \quad\item $M$ is the $(r1+r2)\times n$ matrix whose columns represent + the numerical values of the conjugates of the elements of the integral + basis. + + \quad\item $G$ is an $n\times n$ matrix such that $T2 = {}^{t} G G$, + where $T2$ is the quadratic form $T_{2}(x) = \sum |\sigma(x)|^{2}$, $\sigma$ + running over the embeddings of $K$ into $\C$. + + \quad\item \var{roundG} is a rescaled copy of $G$, rounded to nearest + integers. + + \quad\item $T$ is the $n\times n$ matrix whose coefficients are + $\text{Tr}(\omega_{i}\omega_{j})$ where the $\omega_{i}$ are the elements of + the integral basis. Note also that $\det(T)$ is equal to the discriminant of + the field $K$. Also, when understood as an ideal, the matrix $T^{-1}$ + generates the codifferent ideal. + + \quad\item The columns of $MD$ (\kbd{\var{nf}.diff}) express a $\Z$-basis + of the different of $K$ on the integral basis. + + \quad\item \var{TI} is equal to the primitive part of $T^{-1}$, which has + integral coefficients. + + \quad\item \var{MDI} is a two-element representation (for faster + ideal product) of $d(K)$ times the codifferent ideal + (\kbd{\var{nf}.disc$*$\var{nf}.codiff}, which is an integral ideal). This is + used in \tet{idealinv}. + + \quad\item \var{vP} is the list of prime divisors of the field discriminant, + i.e, the ramified primes (\kbd{\var{nf}.p}); \kbd{nfdiscfactors(nf)} is the + preferred way to access that information. + + $\var{nf}[6]$ is the vector containing the $r1+r2$ roots + (\kbd{\var{nf}.roots}) of $\var{nf}[1]$ corresponding to the $r1+r2$ + embeddings of the number field into $\C$ (the first $r1$ components are real, + the next $r2$ have positive imaginary part). + + $\var{nf}[7]$ is a $\Z$-basis for $d\Z_{K}$, where $d = [\Z_{K}:\Z(\theta)]$, + expressed on the powers of $\theta$. The multiplication by + $d$ ensures that all polynomials have integral coefficients + and $\var{nf}[7] / d$ (\kbd{\var{nf}.zk}) is an integral basis for $\Z_{K}$. + Its first element is guaranteed to be $1$. This basis is LLL-reduced with + respect to $T_{2}$ (strictly speaking, it is a permutation of such a basis, + due to the condition that the first element be $1$). + + $\var{nf}[8]$ is the $n\times n$ integral matrix expressing the power + basis in terms of the integral basis, and finally + + $\var{nf}[9]$ is the $n\times n^{2}$ matrix giving the multiplication table + of the integral basis. + + If a non monic or non integral polynomial is input, \kbd{nfinit} will + transform it, and return a structure attached to the new (monic integral) + polynomial together with the attached change of variables, see $\fl=3$. + It is allowed, though not very useful given the existence of + \tet{nfnewprec}, to input a \var{nf} or a \var{bnf} instead of a polynomial. + It is also allowed to input a \var{rnf}, in which case an \kbd{nf} structure + attached to the absolute defining polynomial \kbd{polabs} is returned (\fl is + then ignored). + + \bprog + ? nf = nfinit(x^3 - 12); \\ initialize number field Q[X] / (X^3 - 12) + ? nf.pol \\ defining polynomial + %2 = x^3 - 12 + ? nf.disc \\ field discriminant + %3 = -972 + ? nf.index \\ index of power basis order in maximal order + %4 = 2 + ? nf.zk \\ integer basis, lifted to Q[X] + %5 = [1, x, 1/2*x^2] + ? nf.sign \\ signature + %6 = [1, 1] + ? factor(abs(nf.disc )) \\ determines ramified primes + %7 = + [2 2] + + [3 5] + ? idealfactor(nf, 2) + %8 = + [[2, [0, 0, -1]~, 3, 1, [0, 1, 0]~] 3] \\ @com $\goth{p}_{2}^{3}$ + @eprog + + \misctitle{Huge discriminants, helping nfdisc} + + In case \var{pol} has a huge discriminant which is difficult to factor, + it is hard to compute from scratch the maximal order. The following + special input formats are also accepted: + + \item $[\var{pol}, B]$ where \var{pol} is a monic integral polynomial and + $B$ is the lift of an integer basis, as would be computed by \tet{nfbasis}: + a vector of polynomials with first element $1$ (implicitly modulo \var{pol}). + This is useful if the maximal order is known in advance. + + \item $[\var{pol}, B, P]$ where \var{pol} and $B$ are as above + (a monic integral polynomial and the lift of an integer basis), and $P$ is + the list of ramified primes in the extension. + + \item $[\var{pol}, \kbd{listP}]$ where \var{pol} is a rational polynomial and + \kbd{listP} specifies a list of primes as in \tet{nfbasis}. Instead of the + maximal order, \kbd{nfinit} then computes + an order which is maximal at these particular primes as well as the primes + contained in the private prime table, see \tet{addprimes}. The result has + a good chance of being correct when the discriminant \kbd{nf.disc} factors + completely over this set of primes but this is not guaranteed. The function + \tet{nfcertify} automates this: + \bprog + ? pol = polcompositum(x^5 - 101, polcyclo(7))[1]; + ? nf = nfinit( [pol, 10^3] ); + ? nfcertify(nf) + %3 = [] + @eprog\noindent A priori, \kbd{nf.zk} defines an order which is only known + to be maximal at all primes $\leq 10^{3}$ (no prime $\leq 10^{3}$ divides + \kbd{nf.index}). The certification step proves the correctness of the + computation. Had it failed, that particular \kbd{nf} structure could + not have been trusted and may have caused routines using it to fail randomly. + One particular function that remains trustworthy in all cases is + \kbd{idealprimedec} when applied to a prime included in the above list + of primes or, more generally, a prime not dividing any entry in + \kbd{nfcertify} output. + \medskip + In order to explain the meaning of $\fl$, let $P = + \kbd{polredbest}(\var{pol})$, a polynomial defining the same number field + obtained using the LLL algorithm on the lattice $(\Z_{K}, T_{2})$, which may be + equal to \var{pol} but is usually different and simpler. Binary digits of + $\fl$ mean: + + \item $1$: return $[\var{nf},\kbd{Mod}(a,P)]$, where $\var{nf}$ is + \kbd{nfinit}$(P)$ and $\kbd{Mod}(a,P)=\kbd{Mod}(x,\var{pol})$ gives the + change of variables. If only this bit is set, the behaviour is useless since + we have $P = \var{pol}$. + + \item $2$: return \kbd{nfinit}$(P)$. + + Both flags are set automatically when \var{pol} is not monic or not + integral: first a linear change of variables is performed, to get a monic + integral polynomial, then \kbd{polredbest}. + + \item $4$: do not LLL-reduce \kbd{nf.zk}, which saves time in large degrees, + you may expect to gain a factor $2$ or so in degree $n\geq 100$ or more, at + the expense of \emph{possibly} slowing down later uses of the \var{nf} + structure. Use this flag if you only need basic arithmetic + (the \kbd{nfelt*}, \kbd{nfmodpr*} and \kbd{ideal*} functions); or if you + expect the natural basis of the maximal order to contain small elements, this + will be the case for cyclotomic fields for instance. On the other hand, + functions involving LLL reduction of rank + $n$ lattices should be avoided since each call will be about as costly as the + initial LLL reduction that the flag prevents and may become more costly + because of this missing initial reduction. In particular it is silly to use + this flag in addition to the first two, although GP will not protest. + + \bprog + ? T = polcyclo(307); + ? K = nfinit(T); + time = 19,390 ms. + ? a = idealhnf(K,1-x); + time = 477ms + ? idealfactor(K, a) + time = 294ms + + ? Kno = nfinit(T, 4); + time = 11,256 ms. + ? ano = idealhnf(Kno,1-x); \\ no slowdown, even sligthly faster + time = 460ms + ? idealfactor(Kno, ano) + time = 264ms + + ? nfinit(T, 2); \\ polredbest is very slow in high degree + time = 4min, 34,870 ms. + ? norml2(%.pol) == norml2(T) \\ and gains nothing here + %9 = 1 + @eprog +Variant: Also available are + \fun{GEN}{nfinit}{GEN x, long prec} ($\fl = 0$), + \fun{GEN}{nfinitred}{GEN x, long prec} ($\fl = 2$), + \fun{GEN}{nfinitred2}{GEN x, long prec} ($\fl = 3$). + Instead of the above hardcoded numerical flags in \kbd{nfinit0}, one should + rather use an or-ed combination of + + \item \tet{nf_RED}: find a simpler defining polynomial, + + \item \tet{nf_ORIG}: also return the change of variable, + + \item \tet{nf_NOLLL}: do not LLL-reduce the maximal order $\Z$-basis. + +Function: nfisideal +Class: basic +Section: number_fields +C-Name: isideal +Prototype: lGG +Help: nfisideal(nf,x): true(1) if x is an ideal in the number field nf, + false(0) if not. +Doc: returns 1 if $x$ is an ideal in the number field $\var{nf}$, 0 otherwise. + +Function: nfisincl +Class: basic +Section: number_fields +C-Name: nfisincl0 +Prototype: GGD0,L, +Help: nfisincl(f,g,{flag=0}): let f and g define number fields, either + irreducible rational polynomials or number fields as output by nfinit; tests + whether the number field f is isomorphic to a subfield of g. Return 0 if not, + and otherwise all the embeddings (flag=0, default), only one (flag=1), or + all embeddings as rational functions (flag=2). +Description: + (gen, gen, ?0):gen nfisincl($1, $2) + (gen, gen, small):gen nfisincl0($1, $2, $3) +Doc: let $f$ and $g$ define number fields, where $f$ and $g$ are irreducible + polynomials in $\Q[X]$ and \var{nf} structures as output by \kbd{nfinit}. + If either $f$ or $g$ is not irreducible, the result is undefined. + Tests whether the number field $f$ is conjugate to a subfield of the field + $g$. If not, the output is the integer 0; if it is, the output depends on + the value of $\fl$: + + \item $\fl = 0$ (default): return a vector of polynomials + $[a_{1},\dots,a_{n}]$ + with rational coefficients, representing all distinct embeddings: we have + $g\mid f\circ a_{i}$ for all $i$. + + \item $\fl = 1$: return a single polynomial $a$ representing a single + embedding; this can be $n$ times faster than the default when the + embeddings have huge coefficients. + + \item $\fl = 2$: return a vector of rational functions $[r_{1},\dots,r_{n}]$ + whose denominators are coprime to $g$ and such that $r_{i} \% g$ is the + polynomial $a_{i}$ from $\fl = 0$. This variant is always faster than $\fl = 0$ + but produces results which are harder to use. If the denominators are hard to + invert in $\Q[X]/(g)$, this may be even faster than $\fl = 1$. + \bprog + ? T = x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10; + ? U = x^3 + 3*x^2 + 3*x - 2 + ? nfisincl(U, T) + %3 = [24/179*x^5-27/179*x^4+80/179*x^3-234/179*x^2+380/179*x+94/179] + ? a = nfisincl(U, T, 1) + %4 = 24/179*x^5-27/179*x^4+80/179*x^3-234/179*x^2+380/179*x+94/179 + ? subst(U, x, Mod(a,T)) + %5 = Mod(0, x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10) + ? nfisincl(U, T, 2) \\ a as a t_RFRAC + %6 = [(2*x^3 - 3*x^2 + 2*x + 4)/(3*x^2 - 1)] + ? (a - %[1]) % T + %7 = 0 + ? #nfisincl(x^2+1, T) \\ two embeddings + %8 = 2 + + \\ same result with nf structures + ? L = nfinit(T); K = nfinit(U); v = [a]; + ? nfisincl(U, L) == v + %10 = 1 + ? nfisincl(K, T) == v + %11 = 1 + ? nfisincl(K, L) == v + %12 = 1 + + \\ comparative bench: an nf is a little faster, esp. for the subfield + ? B = 2000; + ? for (i=1, B, nfisincl(U,T)) + time = 1,364 ms. + ? for (i=1, B, nfisincl(K,T)) + time = 988 ms. + ? for (i=1, B, nfisincl(U,L)) + time = 1,341 ms. + ? for (i=1, B, nfisincl(K,L)) + time = 880 ms. + @eprog\noindent Using an \var{nf} structure for the tentative subfield is + faster if the structure is already available. On the other hand, the gain in + \kbd{nfisincl} is usually not sufficient to make it worthwhile to initialize + only for that purpose. + \bprog + ? for (i=1, B, nfinit(U)) + time = 590 ms. + @eprog\noindent A final more complicated example + \bprog + ? f = x^8 - 72*x^6 + 1944*x^4 - 30228*x^2 - 62100*x - 34749; + ? g = nfsplitting(f); poldegree(g) + %2 = 96 + ? #nfisincl(f, g) + time = 559 ms. + %3 = 8 + ? nfisincl(f,g,1); + time = 172 ms. + ? v = nfisincl(f,g,2); + time = 199 ms. + ? apply(x->poldegree(denominator(x)), v) + %6 = [81, 81, 81, 81, 81, 81, 80, 81] + ? v % g; + time = 407 ms. + @eprog\noindent This final example shows that mapping rational functions to + $\Q[X]/(g)$ can be more costly than that the rest of the algorithm. Note that + \kbd{nfsplitting} also admits a $\fl$ yielding an embedding. +Variant: Also available is + \fun{GEN}{nfisisom}{GEN a, GEN b} ($\fl = 0$). + +Function: nfisisom +Class: basic +Section: number_fields +C-Name: nfisisom +Prototype: GG +Help: nfisisom(f,g): as nfisincl but tests whether f is isomorphic to g. +Doc: as \tet{nfisincl}, but tests for isomorphism. More efficient if + $f$ or $g$ is a number field structure. + \bprog + ? f = x^6 + 30*x^5 + 495*x^4 + 1870*x^3 + 16317*x^2 - 22560*x + 59648; + ? g = x^6 + 42*x^5 + 999*x^4 + 8966*x^3 + 36117*x^2 + 21768*x + 159332; + ? h = x^6 + 30*x^5 + 351*x^4 + 2240*x^3 + 10311*x^2 + 35466*x + 58321; + + ? #nfisisom(f,g) \\ two isomorphisms + %3 = 2 + ? nfisisom(f,h) \\ not isomorphic + %4 = 0 + \\ comparative bench + ? K = nfinit(f); L = nfinit(g); B = 10^3; + ? for (i=1, B, nfisisom(f,g)) + time = 6,124 ms. + ? for (i=1, B, nfisisom(K,g)) + time = 3,356 ms. + ? for (i=1, B, nfisisom(f,L)) + time = 3,204 ms. + ? for (i=1, B, nfisisom(K,L)) + time = 3,173 ms. + @eprog\noindent + The function is usually very fast when the fields are nonisomorphic, + whenever the fields can be distinguished via a simple invariant such as + degree, signature or discriminant. It may be slower when the fields + share all invariants, but still faster than computing actual isomorphisms: + \bprog + \\ usually very fast when the answer is 'no': + ? for (i=1, B, nfisisom(f,h)) + time = 32 ms. + + \\ but not always + ? u = x^6 + 12*x^5 + 6*x^4 - 377*x^3 - 714*x^2 + 5304*x + 15379 + ? v = x^6 + 12*x^5 + 60*x^4 + 166*x^3 + 708*x^2 + 6600*x + 23353 + ? nfisisom(u,v) + %13 = 0 + ? polsturm(u) == polsturm(v) + %14 = 1 + ? nfdisc(u) == nfdisc(v) + %15 = 1 + ? for(i=1,B, nfisisom(u,v)) + time = 1,821 ms. + ? K = nfinit(u); L = nfinit(v); + ? for(i=1,B, nfisisom(K,v)) + time = 232 ms. + @eprog + +Function: nfislocalpower +Class: basic +Section: number_fields +C-Name: nfislocalpower +Prototype: lGGGG +Help: nfislocalpower(nf,pr,a,n): true(1) if a is an n-th power in + the local field K_v, false(0) if not. +Doc: Let \var{nf} be a \var{nf} structure attached to a number field $K$, + let $a \in K$ and let \var{pr} be a \var{prid} structure attached to a + maximal ideal $v$. Return $1$ if $a$ is an $n$-th power in the completed + local field $K_{v}$, and $0$ otherwise. + \bprog + ? K = nfinit(y^2+1); + ? P = idealprimedec(K,2)[1]; \\ the ramified prime above 2 + ? nfislocalpower(K,P,-1, 2) \\ -1 is a square + %3 = 1 + ? nfislocalpower(K,P,-1, 4) \\ ... but not a 4-th power + %4 = 0 + ? nfislocalpower(K,P,2, 2) \\ 2 is not a square + %5 = 0 + + ? Q = idealprimedec(K,5)[1]; \\ a prime above 5 + ? nfislocalpower(K,Q, [0, 32]~, 30) \\ 32*I is locally a 30-th power + %7 = 1 + @eprog + +Function: nfkermodpr +Class: basic +Section: number_fields +C-Name: nfkermodpr +Prototype: GGG +Obsolete: 2016-08-09 +Help: nfkermodpr(nf,x,pr): this function is obsolete, use nfmodpr. +Doc: this function is obsolete, use \kbd{nfmodpr}. + + Kernel of the matrix $a$ in $\Z_{K}/\var{pr}$, where \var{pr} is in + \key{modpr} format (see \kbd{nfmodprinit}). +Variant: This function is normally useless in library mode. Project your + inputs to the residue field using \kbd{nfM\_to\_FqM}, then work there. + +Function: nflist +Class: basic +Section: number_fields +C-Name: nflist +Prototype: GDGD-1,L,DG +Help: nflist(G,{N},{s=-1},{F}): finds number fields (up to isomorphism) + with Galois group of Galois closure isomorphic to G, and s complex places. + + If s = -1 (default) all signatures, s = -2 is identical to s = -1 except + fields are separated by increasing number of complex places. If field F is + specified (by a polynomial), gives only number fields having F as a subfield + (or a resolvent field in the case of S3, Dl, A4, S4, F5, M21 and M42). + + The parameter N can be the following: a positive integer (absolute + value of discriminant is N); a vector [a,b] (finds fields with absolute + discriminant between a and b); a polynomial, in variable t say (regular + extension of Q(t) with specified Galois group). If omitted + (default), returns a few fields and F is ignored. +Doc: finds number fields (up to isomorphism) with Galois group of Galois + closure isomorphic to $G$ with $s$ complex places. The number fields are + given by polynomials. This function supports the following groups: + + \item degree $2$: $C_{2}=2T1$; + + \item degree $3$: $C_{3}=3T1$ and $S_{3}=3T2$; + + \item degree $4$: $C_{4}=4T1$, $V_{4}=4T2$, $D_{4}=4T3$, $A_{4}=4T4$ + and $S_{4}=4T5$; + + \item degree $5$: $C_{5}=5T1$, $D_{5}=5T2$, $F_{5} = M_{{}20}=5T3$ + and $A_{5}=5T4$; + + \item degree $6$: $C_{6}=6T1$, $S_{3}(6) = D_{6}(6)=6T2$, $D_{6}(12)=6T3$, + $A_{4}(6)=6T4$, $S_{3}\times C_{3}=6T5$, $A_{4}(6)\times C_{2}=6T6$, + $S_{4}(6)^{+}=6T7$, $S_{4}(6)^{-}=6T8$, $S_{3}^{2}=6T9$, + $C_{3}^{2}:C_{4}=6T10$, $S_{4}(6)\times C_{2}=6T11$, + $A_{5}(6)=PSL_{2}(5)=6T12$ and $C_{3}^{2}:D_{4}=6T13$; + + \item degree $7$: $C_{7}=7T1$, $D_{7}=7T2$, $M_{{}21}=7T3$ and $M_{{}42}=7T4$; + + \item degree $9$: $C_{9}=9T1$, $C_{3}\times C_{3}=9T2$ and $D_{9}=9T3$; + + \item degree $\ell$ with $\ell$ prime: $C_{\ell}=\ell T1$ and + $D_{\ell}=\ell T2$. + + The groups $A_{5}$ and $A_{5}(6)$ require the optional package + \kbd{nflistdata}. + + In addition, if $N$ is a polynomial, all transitive subgroups of $S_{n}$ + with $n\le 15$, as well as alternating groups $A_{n}$ and the full symmetric + group $S_{n}$ for all $n$ (see below for details and explanations). + + The groups are coded as $[n,k]$ using the \kbd{nTk} format where $n$ is the + degree and $k$ is the $T$-number, the index in the classification of + transitive subgroups of $S_{n}$. + + Alternatively, the groups $C_{n}$, $D_{n}$, $A_{n}$, $S_{n}$, + $V_{4}$, $F_{5} = M_{20}$, $M_{21}$ and $M_{42}$ can be input as + character strings exactly as written, lifting subscripts; for instance + \kbd{"S4"} or \kbd{"M21"}. If the group is not recognized or is + unsupported the function raises an exception. + + The number fields are computed on the fly (and not from a preexisting table) + using a variety of algorithms, with the exception of $A_{5}$ and $A_{5}(6)$ + which are obtained by table lookup. + The algorithms are recursive and use the following ingredients: build + distinguished subfields (or resolvent fields in Galois closures) of smaller + degrees, use class field theory to build abelian extensions over a known + base, select subfields using Galois theory. Because of our use of class + field theory, and ultimately \kbd{bnfinit}, all results depend on the GRH in + degree $n > 3$. + + To avoid wasting time, the output polynomials defining the number fields are + usually not the simplest possible, use \kbd{polredbest} or \kbd{polredabs} + to reduce them. + + The non-negative integer $s$ specifies the number of complex places, between + $0$ and $n/2$. Additional supported values are: + + \item $s = -1$ (default) all signatures; + + \item $s = -2$ all signatures, given by increasing number of complex + places; in degree $n$, this means a vector with $1 + \text{floor}(n/2)$ + components: the $i$-th entry corresponds to $s = i - 1$. + + If the irreducible monic polynomial $F\in \Z[X]$ is specified, gives only + number fields having $\Q[X]/(F)$ as a subfield, or in the case of + $S_{3}$, $D_{\ell}$, $A_{4}$, $S_{4}$, $F_{5}$, $M_{21}$ and $M_{42}$, + as a resolvent field (see also the function \kbd{nfresolvent} for these cases). + + The parameter $N$ can be the following: + + \item a positive integer: finds all fields with absolute discriminant $N$ + (recall that the discriminant over $\Q$ is $(-1)^{s} N$). + + \item a pair of non-negative real numbers $[a,b]$ specifying a real interval: + finds all fields with absolute value of discriminant between $a$ and $b$. + For most Galois groups, this is faster than iterating on individual $N$. + + \item omitted (default): a few fields of small discriminant (not always + those with smallest absolute discriminant) are output with given $G$ + and $s$; usually about 10, less if too difficult to find. The parameter + $F$ is ignored. + + \item a polynomial with main variable, say $t$, of priority lower than $x$. + The program outputs a \emph{regular} polynomial in $\Q(t)[x]$ (in fact in + $\Z[x,t]$) with the given Galois group. By Hilbert irreducibility, almost all + specializations of $t$ will give suitable polynomials. The parameters $s$ and + $F$ are ignored. This is implemented for all transitive subgroups of + $S_{n}$ with $n\le15$ as well as for the alternating and symmetric groups + $A_{n}$ and $S_{n}$ for all $n$. + Polynomials for $A_{n}$ were inspired by J.-F.~Mestre, a few polynomials in + degree $\leq 8$ come from G.~W.~Smith, ``Some polynomials over $\Q(t)$ and + their Galois groups'', \emph{Math. Comp.}, {\bf 69} (230), 1999, pp.~775--796 + most others in degree $\leq 11$ were provided by J.~Kl\"uners and G.~Malle + (see G.~Malle and B.~H.~Matzat, \emph{Inverse Galois Theory}, Springer, + 1999) and T.~Dokchitser completed the list up to degree~$15$. But for + $A_{n}$ and $S_{n}$, subgroups of $S_{n}$ for $n > 7$ require the optional + \kbd{nflistdata} package. + + \misctitle{Complexity} : For a positive integer $N$, the complexity is + subexponential in $\log N$ (and involves factoring $N$). For an interval + $[a,b]$, the complexity is roughly as follows, ignoring terms which are + subexponential in $\log b$. It is usually linear in the output size. + + \item $C_{n}$: $O(b^{1/\phi(n)})$ for $n = 2, 4, 6, 9$ or any odd prime; + + \item $D_{n}$: $O(b^{2/\phi(n)})$ for $n = 4$ or any odd prime; + + \item $V_{4}$, $A_{4}$: $O(b^{1/2})$, $S_{4}$: $O(b)$; + N.B. The subexponential terms are expensive for $A_{4}$ and $S_{4}$. + + \item $M_{20}$: $O(b)$. + + \item $S_{4}(6)^{-}$, $S_{4}(6)^{+}$ $A_{4}(6)\times C_{2}$, + $S_{3}\times S_{3}$, $S_{4}(6)\times C_{2}$ : $O(b)$, + $D_{6}(12)$, $A_{4}(6)$, $S_{3}(6)$, $S_{3}\times C_{3}$, $C_{3}^{2}:C_{4}$: + $O(b^{1/2})$. + + \item $M_{21}$, $M_{42}$: $O(b)$. + + \item $C_{3}\times C_{3}$: $O(b^{1/3})$, $D_{9}$: $O(b^{5/12})$. + + \bprog + ? #nflist("S3", [1, 10^5]) \\ S3 cubic fields + %1 = 21794 + ? #nflist("S3", [1, 10^5], 0) \\ real S3 cubic fields (0 complex place) + %2 = 4753 + ? #nflist("S3", [1, 10^5], 1) \\ complex cubic fields (1 complex place) + %3 = 17041 + ? v = nflist("S3", [1, 10^5], -2); apply(length,v) + %4 = [4753, 17041] + ? nflist("S4") \\ a few S4 fields + %5 = [x^4 + 12*x^2 - 8*x + 16, x^4 - 2*x^2 - 8*x + 25, ...] + ? nflist("S4",,0) \\ a few real S4 fields + %6 = [x^4 - 52*x^2 - 56*x + 48, x^4 - 26*x^2 - 8*x + 1, ...] + ? nflist("S4",,-2) \\ a few real S4 fields, by signature + %7 = [[x^4 - 52*x^2 - 56*x + 48, ...], + [x^4 - 8*x - 16, ... ], + [x^4 + 138*x^2 - 8*x + 4541, ...]] + ? nflist("S3",,,x^2+23) \\ a few cubic fields with resolvent Q(sqrt(-23)) + %8 = [x^3 + x + 1, x^3 + 2*x + 1, ...] + ? nflist("C3", 3969) \\ C3 fields of given discriminant + %9 = [x^3 - 21*x + 28, x^3 - 21*x - 35] + ? nflist([3,1], 3969) \\ C3 fields, using nTt label + %10 = [x^3 - 21*x + 28, x^3 - 21*x - 35] + ? P = nflist([8,12],t) \\ geometric 8T12 polynomial + %11 = x^8 + (-t^2 - 803)*x^6 + (264*t^2 + 165528)*x^4 + + (-2064*t^2 - 1724976)*x^2 + 4096*t^2 + ? polgalois(subst(P, t, 11)) + %12 = [24, 1, 12, "2A_4(8)=[2]A(4)=SL(2,3)"] + ? nflist("S11") + *** at top-level: nflist("S11") + *** ^------------- + *** nflist: unsupported group (S11). Use one of + "C1"=[1,1]; + "C2"=[2,1]; + "C3"=[3,1], "S3"=[3,2]; + "C4"=[4,1], "V4"=[4,2], "D4"=[4,3], "A4"=[4,4], "S4"=[4,5]; + "C5"=[5,1], "D5"=[5,2], "F5"="M20"=[5,3], "A5"=[5,4]; + "C6"=[6,1], "D6"=[6,2], [6,3], ..., [6,13]; + "C7"=[7,1], "D7"=[7,2], "M21"=[7,3], "M42"=[7,4]; + "C9"=[9,1], [9,2], "D9"=[9,3]." + Also supported are "Cp"=[p,1] and "Dp"=[p,2] for any odd prime p. + + ? nflist("S25", 't) + %13 = x^25 + x*t + 1 + @eprog + +Function: nfmodpr +Class: basic +Section: number_fields +C-Name: nfmodpr +Prototype: GGG +Help: nfmodpr(nf,x,pr): map x to the residue field mod pr. +Doc: map $x$ to a \typ{FFELT} in the residue field modulo \var{pr}. + The argument \var{pr} is either a maximal ideal in \kbd{idealprimedec} + format or, preferably, a \var{modpr} structure from \tet{nfmodprinit}. The + function \tet{nfmodprlift} allows to lift back to $\Z_{K}$. + + Note that the function applies to number field elements and not to + vector / matrices / polynomials of such. Use \kbd{apply} to convert + recursive structures. + \bprog + ? K = nfinit(y^3-250); + ? P = idealprimedec(K, 5)[2]; + ? modP = nfmodprinit(K, P, 't); + ? K.zk + %4 = [1, 1/5*y, 1/25*y^2] + ? apply(t->nfmodpr(K,t,modP), K.zk) + %5 = [1, t, 2*t + 1] + ? %[1].mod + %6 = t^2 + 3*t + 4 + ? K.index + %7 = 125 + @eprog\noindent For clarity, we represent elements in the residue + field $\F_{5}[t]/(T)$ as polynomials in the variable $t$. Whenever the + underlying rational prime does not divide \kbd{K.index}, it is actually + the case that $t$ is the reduction of $y$ in $\Q[y]/(\kbd{K.pol})$ + modulo an irreducible factor of \kbd{K.pol} over $\F_{p}$. In the above + example, $5$ divides the index and $t$ is actually the reduction of $y/5$. + +Function: nfmodprinit +Class: basic +Section: number_fields +C-Name: nfmodprinit0 +Prototype: GGDn +Help: nfmodprinit(nf,pr,{v=variable(nf.pol)}): transform the prime ideal pr + into modpr format necessary for all operations mod pr in the number field nf. + Variable v is used to display finite field elements (see ffgen). +Doc: transforms the prime ideal \var{pr} into \tet{modpr} format necessary + for all operations modulo \var{pr} in the number field \var{nf}. + The functions \tet{nfmodpr} and \tet{nfmodprlift} allow to project + to and lift from the residue field. The variable $v$ is used to display + finite field elements (see \kbd{ffgen}). + \bprog + ? K = nfinit(y^3-250); + ? P = idealprimedec(K, 5)[2]; + ? modP = nfmodprinit(K, P, 't); + ? K.zk + %4 = [1, 1/5*y, 1/25*y^2] + ? apply(t->nfmodpr(K,t,modP), K.zk) + %5 = [1, t, 2*t + 1] + ? %[1].mod + %6 = t^2 + 3*t + 4 + ? K.index + %7 = 125 + @eprog\noindent For clarity, we represent elements in the residue + field $\F_{5}[t]/(T)$ as polynomials in the variable $t$. Whenever the + underlying rational prime does not divide \kbd{K.index}, it is actually + the case that $t$ is the reduction of $y$ in $\Q[y]/(\kbd{K.pol})$ + modulo an irreducible factor of \kbd{K.pol} over $\F_{p}$. In the above + example, $5$ divides the index and $t$ is actually the reduction of $y/5$. + +Function: nfmodprlift +Class: basic +Section: number_fields +C-Name: nfmodprlift +Prototype: GGG +Help: nfmodprlift(nf,x,pr): lift x from residue field mod pr to nf. +Doc: lift the \typ{FFELT} $x$ (from \tet{nfmodpr}) in the residue field + modulo \var{pr} to the ring of integers. Vectors and matrices are also + supported. For polynomials, use \kbd{apply} and the present function. + + The argument \var{pr} is either a maximal ideal in \kbd{idealprimedec} + format or, preferably, a \var{modpr} structure from \tet{nfmodprinit}. + There are no compatibility checks to try and decide whether $x$ is attached + the same residue field as defined by \var{pr}: the result is undefined + if not. + + The function \tet{nfmodpr} allows to reduce to the residue field. + \bprog + ? K = nfinit(y^3-250); + ? P = idealprimedec(K, 5)[2]; + ? modP = nfmodprinit(K,P); + ? K.zk + %4 = [1, 1/5*y, 1/25*y^2] + ? apply(t->nfmodpr(K,t,modP), K.zk) + %5 = [1, y, 2*y + 1] + ? nfmodprlift(K, %, modP) + %6 = [1, 1/5*y, 2/5*y + 1] + ? nfeltval(K, %[3] - K.zk[3], P) + %7 = 1 + @eprog + +Function: nfnewprec +Class: basic +Section: number_fields +C-Name: nfnewprec +Prototype: Gp +Help: nfnewprec(nf): transform the number field data nf into new data using + the current (usually larger) precision. +Doc: transforms the number field $\var{nf}$ + into the corresponding data using current (usually larger) precision. This + function works as expected if \var{nf} is in fact a \var{bnf}, a \var{bnr} + or a \var{rnf} (update structure to current precision). \emph{If} the original + \var{bnf} structure was \emph{not} computed by \kbd{bnfinit(,1)}, then + this may be quite slow and even fail: many + generators of principal ideals have to be computed and the algorithm may + fail because the accuracy is not sufficient to bootstrap the + required generators and fundamental units. +Variant: See also \fun{GEN}{bnfnewprec}{GEN bnf, long prec} and + \fun{GEN}{bnrnewprec}{GEN bnr, long prec}. + +Function: nfpolsturm +Class: basic +Section: number_fields +C-Name: nfpolsturm +Prototype: GGDG +Help: nfpolsturm(nf,T,{pl}): number of distinct real roots of the polynomial + s(T) where s runs through the real embeddings given by vector pl. +Doc: given a polynomial $T$ with coefficients in the number field \var{nf}, + returns the number of real roots of the $s(T)$ where $s$ runs through + the real embeddings of the field specified by optional argument \var{pl}: + + \item \var{pl} omitted: all $r_{1}$ real places; + + \item \var{pl} an integer between $1$ and $r_{1}$: the embedding attached to + the $i$-th real root of \kbd{nf.pol}, i.e. \kbd{nf.roots$[i]$}; + + \item \var{pl} a vector or \typ{VECSMALL}: the embeddings + attached to the $\var{pl}[i]$-th real roots of \kbd{nf.pol}. + + \bprog + ? nf = nfinit('y^2 - 2); + ? nf.sign + %2 = [2, 0] + ? nf.roots + %3 = [-1.414..., 1.414...] + ? T = x^2 + 'y; + ? nfpolsturm(nf, T, 1) \\ subst(T,y,sqrt(2)) has two real roots + %5 = 2 + ? nfpolsturm(nf, T, 2) \\ subst(T,y,-sqrt(2)) has no real root + %6 = 0 + ? nfpolsturm(nf, T) \\ all embeddings together + %7 = [2, 0] + ? nfpolsturm(nf, T, [2,1]) \\ second then first embedding + %8 = [0, 2] + ? nfpolsturm(nf, x^3) \\ number of distinct roots ! + %9 = [1, 1] + ? nfpolsturm(nf, x, 6) \\ there are only 2 real embeddings ! + *** at top-level: nfpolsturm(nf,x,6) + *** ^----------------- + *** nfpolsturm: domain error in nfpolsturm: index > 2 + @eprog + +Function: nfresolvent +Class: basic +Section: number_fields +C-Name: nfresolvent +Prototype: GD0,L, +Help: nfresolvent(pol,{flag=0}): In the case where the Galois closure of the + number field defined by pol is S3, Dl, A4, S4, F5, A5, M21, or M42, gives the + corresponding resolvent field. Otherwise, give a "canonical" subfield, + or if flag >= 2 all "canonical" subfields. If flag is odd, give also the + "conductor" f, whose definition is specific to each group. +Doc: Let \kbd{pol} be an irreducible integral polynomial defining a number + field $K$ with Galois closure $\tilde{K}$. This function is limited to the + Galois groups supported by \kbd{nflist}; in the following $\ell$ denotes an + odd prime. If $\text{Gal}(\tilde{K}/\Q)$ is $D_{\ell}$, $A_{4}$, $S_{4}$, + $F_{5}$ ($M_{20}$), $A_{5}$, $M_{21}$ or $M_{42}$, + returns a polynomial $R$ defining the corresponding resolvent field (quadratic + for $D_{\ell}$, cyclic cubic for $A_{4}$ and $M_{21}$, noncyclic cubic for + $S_{4}$, cyclic quartic for $F_{5}$, $A_{5}(6)$ sextic for $A_{5}$, and cyclic + sextic for $M_{42}$). In the $A_{5}(6)$ case, returns the $A_{5}$ field of + which it is the resolvent. Otherwise, gives a ``canonical'' subfield, or $0$ + if the Galois group is not supported. + + The binary digits of \fl\ correspond to 1: returns a pair $[R,f]$ where $f$ + is a ``conductor'' whose definition is specific to each group and given + below; 2: returns all ``canonical'' subfields. + + Let $D$ be the discriminant of the resolvent field \kbd{nfdisc}$(R)$: + + \item In cases $C_{\ell}$, $D_{\ell}$, $A_{4}$, or $S_{4}$, $\text{disc}(K) + =(Df^{2})^{m}$ with $m=(\ell-1)/2$ in the first two cases, and $1$ in the last + two. + + \item In cases where $K$ is abelian over the resolvent subfield, the conductor + of the relative extension. + + \item In case $F_{5}$, $\text{disc}(K)=Df^{4}$ if $f>0$ or $5^{2}Df^{4}$ + if $f<0$. + + \item In cases $M_{21}$ or $M_{42}$, $\text{disc}(K)=D^{m}f^{6}$ if $f>0$ or + $7^{3}D^{m}f^{6}$ if $f<0$, where $m=2$ for $M_{21}$ and $m=1$ for $M_{42}$. + + \item In cases $A_{5}$ and $A_{5}(6)$, $\fl$ is currently ignored. + + \bprog + ? pol = x^6-3*x^5+7*x^4-9*x^3+7*x^2-3*x+1; \\ Galois closure D_6 + ? nfresolvent(pol) + %2 = x^3 + x - 1 + ? nfresolvent(pol,1) + %3 = [x^3 + x - 1, [[31, 21, 3; 0, 1, 0; 0, 0, 1], [1]]] + @eprog + +Function: nfroots +Class: basic +Section: number_fields +C-Name: nfroots +Prototype: DGG +Help: nfroots({nf},x): roots of polynomial x belonging to nf (Q if + omitted) without multiplicity. +Doc: roots of the polynomial $x$ in the + number field $\var{nf}$ given by \kbd{nfinit} without multiplicity (in $\Q$ + if $\var{nf}$ is omitted). $x$ has coefficients in the number field (scalar, + polmod, polynomial, column vector). The main variable of $\var{nf}$ must be + of lower priority than that of $x$ (see \secref{se:priority}). However if the + coefficients of the number field occur explicitly (as polmods) as + coefficients of $x$, the variable of these polmods \emph{must} be the same as + the main variable of $t$ (see \kbd{nffactor}). + + It is possible to input a defining polynomial for \var{nf} + instead, but this is in general less efficient since parts of an \kbd{nf} + structure will then be computed internally. This is useful in two + situations: when you do not need the \kbd{nf} elsewhere, or when you cannot + initialize an \kbd{nf} due to integer factorization difficulties when + attempting to compute the field discriminant and maximal order. + + \misctitle{Caveat} \kbd{nfinit([T, listP])} allows to compute in polynomial + time a conditional \var{nf} structure, which sets \kbd{nf.zk} to an order + which is not guaranteed to be maximal at all primes. Always either use + \kbd{nfcertify} first (which may not run in polynomial time) or make sure + to input \kbd{nf.pol} instead of the conditional \var{nf}: \kbd{nfroots} is + able to recover in polynomial time in this case, instead of potentially + missing a factor. +Variant: See also \fun{GEN}{nfrootsQ}{GEN x}, + corresponding to $\kbd{nf} = \kbd{NULL}$. + +Function: nfrootsof1 +Class: basic +Section: number_fields +C-Name: nfrootsof1 +Prototype: G +Help: nfrootsof1(nf): number of roots of unity and primitive root of unity + in the number field nf. +Doc: Returns a two-component vector $[w,z]$ where $w$ is the number of roots of + unity in the number field \var{nf}, and $z$ is a primitive $w$-th root + of unity. It is possible to input a defining polynomial for \var{nf} + instead. + \bprog + ? K = nfinit(polcyclo(11)); + ? nfrootsof1(K) + %2 = [22, [0, 0, 0, 0, 0, -1, 0, 0, 0, 0]~] + ? z = nfbasistoalg(K, %[2]) \\ in algebraic form + %3 = Mod(-x^5, x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) + ? [lift(z^11), lift(z^2)] \\ proves that the order of z is 22 + %4 = [-1, -x^9 - x^8 - x^7 - x^6 - x^5 - x^4 - x^3 - x^2 - x - 1] + @eprog + This function guesses the number $w$ as the gcd of the $\#k(v)^{*}$ for + unramified $v$ above odd primes, then computes the roots in \var{nf} + of the $w$-th cyclotomic polynomial. The algorithm is polynomial time with + respect to the field degree and the bitsize of the multiplication table in + \var{nf} (both of them polynomially bounded in terms of the size of the + discriminant). Fields of degree up to $100$ or so should require less than + one minute. + +Function: nfsnf +Class: basic +Section: number_fields +C-Name: nfsnf0 +Prototype: GGD0,L, +Help: nfsnf(nf,x,{flag=0}): if x=[A,I,J], outputs D=[d_1,...d_n] Smith normal + form of x. If flag is nonzero return [D,U,V], where UAV = Id. +Doc: given a torsion $\Z_{K}$-module $x$ attached to the square integral + invertible pseudo-matrix $(A,I,J)$, returns an ideal list + $D=[d_{1},\dots,d_{n}]$ which is the \idx{Smith normal form} of $x$. In other + words, $x$ is isomorphic to $\Z_{K}/d_{1}\oplus\cdots\oplus\Z_{K}/d_{n}$ + and $d_{i}$ + divides $d_{i-1}$ for $i\ge2$. If $\fl$ is nonzero return $[D,U,V]$, where + $UAV$ is the identity. + + See \secref{se:ZKmodules} for the definition of integral pseudo-matrix; + briefly, it is input as a 3-component row vector $[A,I,J]$ where + $I = [b_{1},\dots,b_{n}]$ and $J = [a_{1},\dots,a_{n}]$ are two ideal lists, + and $A$ is a square $n\times n$ matrix with columns $(A_{1},\dots,A_{n})$, + seen as elements in $K^{n}$ (with canonical basis $(e_{1},\dots,e_{n})$). + This data defines the $\Z_{K}$ module $x$ given by + $$ (b_{1}e_{1}\oplus\cdots\oplus b_{n}e_{n}) + / (a_{1}A_{1}\oplus\cdots\oplus a_{n}A_{n}) \enspace, $$ + The integrality condition is $a_{i,j} \in b_{i} a_{j}^{-1}$ for all $i,j$. + If it + is not satisfied, then the $d_{i}$ will not be integral. Note that every + finitely generated torsion module is isomorphic to a module of this form and + even with $b_{i}=Z_{K}$ for all $i$. +Variant: Also available: + + \fun{GEN}{nfsnf}{GEN nf, GEN x} ($\fl = 0$). + +Function: nfsolvemodpr +Class: basic +Section: number_fields +C-Name: nfsolvemodpr +Prototype: GGGG +Obsolete: 2016-08-09 +Help: nfsolvemodpr(nf,a,b,P): this function is obsolete, use nfmodpr. +Doc: this function is obsolete, use \kbd{nfmodpr}. + + Let $P$ be a prime ideal in \key{modpr} format (see \kbd{nfmodprinit}), + let $a$ be a matrix, invertible over the residue field, and let $b$ be + a column vector or matrix. This function returns a solution of $a\cdot x = + b$; the coefficients of $x$ are lifted to \var{nf} elements. + \bprog + ? K = nfinit(y^2+1); + ? P = idealprimedec(K, 3)[1]; + ? P = nfmodprinit(K, P); + ? a = [y+1, y; y, 0]; b = [1, y]~ + ? nfsolvemodpr(K, a,b, P) + %5 = [1, 2]~ + @eprog +Variant: This function is normally useless in library mode. Project your + inputs to the residue field using \kbd{nfM\_to\_FqM}, then work there. + +Function: nfsplitting +Class: basic +Section: number_fields +C-Name: nfsplitting0 +Prototype: GDGD0,L, +Help: nfsplitting(P,{d},{fl}): defining polynomial S over Q for the splitting + field of P, that is the smallest field over which P is totally split. + P can also be given by a nf structure. If d is given, it must be a multiple + of the splitting field degree. If fl=1, return [S,C] where C is an embedding + of Q[x]/(P) in its splitting field. +Doc: defining polynomial $S$ over~$\Q$ for the splitting field of + $\var{P} \in \Q[x]$, that is the smallest field over which $P$ is totally + split. If irreducible, the polynomial $P$ can also be given by a~\kbd{nf} + structure, which is more efficient. If $d$ is given, it must be a multiple of + the splitting field degree. Note that if $P$ is reducible the splitting field + degree can be smaller than the degree of $P$. + + If $\fl$ is non-zero, we assume $P$ to be monic, integral and irreducible and + the return value depends on $\fl$: + + \item $\fl = 1$: return $[S,C]$ where $S$ is as before and $C$ is an + embedding of $\Q[x]/(P)$ in its splitting field given by a polynomial + (implicitly modulo $S$, as in \kbd{nfisincl}). + + \item $\fl = 2$: return $[S,C]$ where $C$ is vector of rational functions + whose image in $\Q[x]/(S)$ yields the embedding; this avoids inverting the + denominator, which is costly. when the degree of the splitting field is huge. + + \item $\fl = 3$: return $[S, v, p]$ a data structure allowing to quickly + compute the Galois group of the splitting field, which is used by + \kbd{galoissplittinginit}; more precisely, $p$ is a prime splitting + completely in the splitting field and $v$ is a vector with $\deg S$ + elements describing the automorphisms of $S$ acting on the roots + of $S$ modulo $p$. + + \bprog + ? K = nfinit(x^3 - 2); + ? nfsplitting(K) + %2 = x^6 + 108 + ? nfsplitting(x^8 - 2) + %3 = x^16 + 272*x^8 + 64 + ? S = nfsplitting(x^6 - 8) \\ reducible + %4 = x^4 + 2*x^2 + 4 + ? lift(nfroots(subst(S,x,a),x^6-8)) + %5 = [-a, a, -1/2*a^3 - a, -1/2*a^3, 1/2*a^3, 1/2*a^3 + a] + + ? P = x^8-2; + ? [S,C] = nfsplitting(P,,1) + %7 = [x^16 + 272*x^8 + 64, -7/768*x^13 - 239/96*x^5 + 1/2*x] + ? subst(P, x, Mod(C,S)) + %8 = Mod(0, x^16 + 272*x^8 + 64) + @eprog\noindent + Specifying the degree $d$ of the splitting field can make the computation + faster; if $d$ is not a multiple of the true degree, it will be ignored with + a warning. + \bprog + ? nfsplitting(x^17-123); + time = 3,607 ms. + ? poldegree(%) + %2 = 272 + ? nfsplitting(x^17-123,272); + time = 150 ms. + ? nfsplitting(x^17-123,273); + *** nfsplitting: Warning: ignoring incorrect degree bound 273 + time = 3,611 ms. + @eprog + \noindent + The complexity of the algorithm is polynomial in the degree $d$ of the + splitting field and the bitsize of $T$; if $d$ is large the result will + likely be unusable, e.g. \kbd{nfinit} will not be an option: + \bprog + ? nfsplitting(x^6-x-1) + [... degree 720 polynomial deleted ...] + time = 11,020 ms. + @eprog + Variant: Also available is + \fun{GEN}{nfsplitting}{GEN T, GEN D} for $\fl = 0$. + +Function: nfsubfields +Class: basic +Section: number_fields +C-Name: nfsubfields0 +Prototype: GD0,L,D0,L, +Help: nfsubfields(pol,{d=0},{flag=0}): finds all subfields of degree d of number + field defined by pol (all subfields if d is null or omitted). The result is a + vector of subfields, each being given by [g,h] (default) or simply g (flag=1), + where g is an absolute equation and h expresses one of the roots of g in terms + of the root x of the polynomial defining nf. +Doc: finds all subfields of degree + $d$ of the number field defined by the (monic, integral) polynomial + \var{pol} (all subfields if $d$ is null or omitted). The result is a vector + of subfields, each being given by $[g,h]$ (default) or simply $g$ ($\fl=1$), + where $g$ is an absolute equation + and $h$ expresses one of the roots of $g$ in terms of the root $x$ of the + polynomial defining $\var{nf}$. This routine uses + + \item Allombert's \tet{galoissubfields} when \var{nf} is Galois (with weakly + supersolvable Galois group).\sidx{Galois}\sidx{subfield} + + \item Kl\"uners's or van Hoeij--Kl\"uners--Novocin algorithm + in the general case. The latter runs in polynomial time and is generally + superior unless there exists a small unramified prime $p$ such that \var{pol} + has few irreducible factors modulo $p$. + + An input of the form~\kbd{[nf, fa]} is also allowed, where~\kbd{fa} is the + factorisation of~\var{nf.pol} over~\var{nf}, expressed as a famat of + polynomials with coefficients in the variable of~\kbd{nf}, in which case the + van Hoeij--Kl\"uners--Novocin algorithm is used. + + \bprog + ? pol = x^4 - x^3 - x^2 + x + 1; + ? nfsubfields(pol) + %2 = [[x, 0], [x^2 - x + 1, x^3 - x^2 + 1], [x^4 - x^3 - x^2 + x + 1, x]] + ? nfsubfields(pol,,1) + %2 = [x, x^2 - x + 1, x^4 - x^3 - x^2 + x + 1] + ? y=varhigher("y"); fa = nffactor(pol,subst(pol,x,y)); + ? #nfsubfields([pol,fa]) + %5 = 3 + @eprog +Variant: Also available is \fun{GEN}{nfsubfields}{GEN nf, long d}, corresponding + to $\fl = 0$. + +Function: nfsubfieldscm +Class: basic +Section: number_fields +C-Name: nfsubfieldscm +Prototype: GD0,L, +Help: nfsubfieldscm(nf,{flag=0}): computes the maximal CM subfield of nf. + Returns 0 if nf does not have a CM subfield, otherwise returns [g,h] (default) + or g (flag=1) where g is an absolute equation and h expresses a root of g in + terms of the generator of nf. +Doc: Computes the maximal CM subfield of \var{nf}. Returns $0$ if \var{nf} does + not have a CM subfield, otherwise returns~$[g,h]$ (default) or $g$ ($\fl=1$) + where~$g$ is an absolute equation and~$h$ expresses a root of $g$ in terms of + the generator of~\var{nf}. + Moreover, the CM involution is given by $X\bmod g(X) \mapsto -X\bmod g(X)$, + i.e. $X\bmod g(X)$ is a totally imaginary element. + + An input of the form~\kbd{[nf, fa]} is also allowed, where~\kbd{fa} is the + factorisation of~\var{nf.pol} over~\var{nf}, and~\var{nf} is also allowed to + be a monic defining polynomial for the number field. + + \bprog + ? nf = nfinit(x^8 + 20*x^6 + 10*x^4 - 4*x^2 + 9); + ? nfsubfieldscm(nf) + %2 = [x^4 + 4480*x^2 + 3612672, 3*x^5 + 58*x^3 + 5*x] + ? pol = y^16-8*y^14+29*y^12-60*y^10+74*y^8-48*y^6+8*y^4+4*y^2+1; + ? fa = nffactor(pol, subst(pol,y,x)); + ? nfsubfieldscm([pol,fa]) + %5 = [y^8 + ... , ...] + @eprog + +Function: nfsubfieldsmax +Class: basic +Section: number_fields +C-Name: nfsubfieldsmax +Prototype: GD0,L, +Help: nfsubfieldsmax(nf,{flag=0}): computes the list of maximal subfields of + nf. The result is as in nfsubfields. +Doc: Computes the list of maximal subfields of \var{nf}. The result is a vector + as in \tet{nfsubfields}. + + An input of the form~\kbd{[nf, fa]} is also allowed, where~\kbd{fa} is the + factorisation of~\var{nf.pol} over~\var{nf}, and~\var{nf} is also allowed to + be a monic defining polynomial for the number field. + +Function: nfweilheight +Class: basic +Section: number_fields +C-Name: nfweilheight +Prototype: GGp +Help: nfweilheight(nf, v): return the absolute Weil height of the vector v seen + as an element of the projective space over the number field nf given by nfinit. +Doc: let \var{nf} be attached to a number field $K$, let $v$ be a vector of + elements of $K$, not all of them $0$, seen as element of the projective + space of dimension \kbd{\#v - 1}. Return the absolute logarithmic Weil height + of that element, which does not depend on the number field used to compute it. + + When the entries of $v$ are rational, the height is + \kbd{log(normlp(v / content(v), oo))}. + \bprog + ? v = [1, 2, -3, 101]; Q = nfinit(x); Qi = nfinit(x^2 + 1); + ? exponent(nfweilheight(Q, v) - log(101)) + %2 = -125 + ? exponent(nfweilheight(Qi, v) - log(101)) + %3 = -125 + @eprog + +Function: norm +Class: basic +Section: conversions +C-Name: gnorm +Prototype: G +Help: norm(x): norm of x. +Doc: + algebraic norm of $x$, i.e.~the product of $x$ with + its conjugate (no square roots are taken), or conjugates for polmods. For + vectors and matrices, the norm is taken componentwise and hence is not the + $L^{2}$-norm (see \kbd{norml2}). Note that the norm of an element of + $\R$ is its square, so as to be compatible with the complex norm. + +Function: norml2 +Class: basic +Section: linear_algebra +C-Name: gnorml2 +Prototype: G +Help: norml2(x): square of the L2-norm of x. +Doc: square of the $L^{2}$-norm of $x$. More precisely, + if $x$ is a scalar, $\kbd{norml2}(x)$ is defined to be the square + of the complex modulus of $x$ (real \typ{QUAD}s are not supported). + If $x$ is a polynomial, a (row or column) vector or a matrix, \kbd{norml2($x$)} is + defined recursively as $\sum_{i} \kbd{norml2}(x_{i})$, where $(x_{i})$ + run through + the components of $x$. In particular, this yields the usual + $\sum_{i} |x_{i}|^{2}$ (resp.~$\sum_{i,j} |x_{i,j}|^{2}$) if $x$ is a + polynomial or vector (resp.~matrix) with complex components. + + \bprog + ? norml2( [ 1, 2, 3 ] ) \\ vector + %1 = 14 + ? norml2( [ 1, 2; 3, 4] ) \\ matrix + %2 = 30 + ? norml2( 2*I + x ) + %3 = 5 + ? norml2( [ [1,2], [3,4], 5, 6 ] ) \\ recursively defined + %4 = 91 + @eprog + +Function: normlp +Class: basic +Section: linear_algebra +C-Name: gnormlp +Prototype: GDGp +Help: normlp(x,{p=oo}): Lp-norm of x; sup norm if p is omitted. +Description: + (gen):gen:prec gsupnorm($1, $prec) + (gen,):gen:prec gsupnorm($1, $prec) + (gen,1):gen:prec gnorml1($1, $prec) +Doc: + $L^{p}$-norm of $x$; sup norm if $p$ is omitted or \kbd{+oo}. More precisely, + if $x$ is a scalar, \kbd{normlp}$(x, p)$ is defined to be \kbd{abs}$(x)$. + If $x$ is a polynomial, a (row or column) vector or a matrix: + + \item if $p$ is omitted or \kbd{+oo}, then \kbd{normlp($x$)} is defined + recursively as $\max_{i} \kbd{normlp}(x_{i}))$, where $x_{i}$ runs through the + components of~$x$. In particular, this yields the usual sup norm if $x$ is a + polynomial or vector with complex components. + + \item otherwise, \kbd{normlp($x$, $p$)} is defined recursively as + $(\sum_{i} \kbd{normlp}^{p}(x_{i},p))^{1/p}$. In particular, this yields the + usual $(\sum_{i} |x_{i}|^{p})^{1/p}$ if $x$ is a polynomial or vector with + complex components. + + \bprog + ? v = [1,-2,3]; normlp(v) \\ vector + %1 = 3 + ? normlp(v, +oo) \\ same, more explicit + %2 = 3 + ? M = [1,-2;-3,4]; normlp(M) \\ matrix + %3 = 4 + ? T = (1+I) + I*x^2; normlp(T) + %4 = 1.4142135623730950488016887242096980786 + ? normlp([[1,2], [3,4], 5, 6]) \\ recursively defined + %5 = 6 + + ? normlp(v, 1) + %6 = 6 + ? normlp(M, 1) + %7 = 10 + ? normlp(T, 1) + %8 = 2.4142135623730950488016887242096980786 + @eprog + +Function: numbpart +Class: basic +Section: combinatorics +C-Name: numbpart +Prototype: G +Help: numbpart(n): number of partitions of n. +Doc: gives the number of unrestricted partitions of + $n$, usually called $p(n)$ in the literature; in other words the number of + nonnegative integer solutions to $a+2b+3c+\cdots=n$. $n$ must be of type + integer and $n<10^{15}$ (with trivial values $p(n) = 0$ for $n < 0$ and + $p(0) = 1$). The algorithm uses the Hardy-Ramanujan-Rademacher formula. + To explicitly enumerate them, see \tet{partitions}. + +Function: numdiv +Class: basic +Section: number_theoretical +C-Name: numdiv +Prototype: G +Help: numdiv(x): number of divisors of x. +Description: + (gen):int numdiv($1) +Doc: number of divisors of $|x|$. $x$ must be of type integer. + +Function: numerator +Class: basic +Section: conversions +C-Name: numerator +Prototype: GDG +Help: numerator(f,{D}): numerator of f. +Doc: + numerator of $f$. This is defined as \kbd{f * denominator(f,D)}, see + \kbd{denominator} for details. The optional argument $D$ allows to control + over which ring we compute the denominator: + + \item $1$: we only consider the underlying $\Q$-structure and the + denominator is a (positive) rational integer + + \item a simple variable, say \kbd{'x}: all entries as rational functions + in $K(x)$ and the denominator is a polynomial in $x$. + + \bprog + ? f = x + 1/y + 1/2; + ? numerator(f) \\ a t_POL in x + %2 = x + ((y + 2)/(2*y)) + ? numerator(f, 1) \\ Q-denominator is 2 + %3 = x + ((y + 2)/y) + ? numerator(f, y) \\ as a rational function in y + %5 = 2*y*x + (y + 2) + @eprog +Variant: Also available are + \fun{GEN}{numer}{GEN x} which implements the not very useful default + behaviour ($D$ is \kbd{NULL}) and + \fun{GEN}{Q_remove_denom}{GEN x, GEN *ptd} ($D = 1$) and also returns the + denominator (coding $1$ as \kbd{NULL}). + +Function: numtoperm +Class: basic +Section: combinatorics +C-Name: numtoperm +Prototype: LG +Help: numtoperm(n,k): permutation number k (mod n!) of n letters (n + C-integer). +Description: + (small,int):vecsmall Z_to_perm($1, $2) + (small,gen):vecsmall numtoperm($1, $2) +Doc: generates the $k$-th permutation (as a row vector of length $n$) of the + numbers $1$ to $n$. The number $k$ is taken modulo $n!\,$, i.e.~inverse + function of \tet{permtonum}. The numbering used is the standard lexicographic + ordering, starting at $0$. + +Function: omega +Class: basic +Section: number_theoretical +C-Name: omega +Prototype: lG +Help: omega(x): number of distinct prime divisors of x. +Doc: number of distinct prime divisors of $|x|$. $x$ must be of type integer. + \bprog + ? factor(392) + %1 = + [2 3] + + [7 2] + + ? omega(392) + %2 = 2; \\ without multiplicity + ? bigomega(392) + %3 = 5; \\ = 3+2, with multiplicity + @eprog + +Function: oo +Class: basic +Section: conversions +C-Name: mkoo +Prototype: +Help: oo=oo(): infinity. +Doc: returns an object meaning $+\infty$, for use in functions such as + \kbd{intnum}. It can be negated (\kbd{-oo} represents $-\infty$), and + compared to real numbers (\typ{INT}, \typ{FRAC}, \typ{REAL}), with the + expected meaning: $+\infty$ is greater than any real number and $-\infty$ is + smaller. + +Function: padicappr +Class: basic +Section: polynomials +C-Name: padicappr +Prototype: GG +Help: padicappr(pol,a): p-adic roots of the polynomial pol congruent to a mod p. +Doc: vector of $p$-adic roots of the polynomial \var{pol} congruent to the + $p$-adic number $a$ modulo $p$, and with the same $p$-adic precision as $a$. + The number $a$ can be an ordinary $p$-adic number (type \typ{PADIC}, i.e.~an + element of $\Z_{p}$) or can be an integral element of a finite + \emph{unramified} extension $\Q_{p}[X]/(T)$ of $\Q_{p}$, given as a + \typ{POLMOD} + \kbd{Mod}$(A,T)$ at least one of whose coefficients is a \typ{PADIC} and $T$ + irreducible modulo $p$. In this case, the result is the vector of roots + belonging to the same extension of $\Q_{p}$ as $a$. The polynomial \var{pol} + should have exact coefficients; if not, its coefficients are first rounded + to $\Q$ or $\Q[X]/(T)$ and this is the polynomial whose roots we consider. +Variant: Also available is \fun{GEN}{Zp_appr}{GEN f, GEN a} when $a$ is a + \typ{PADIC}. + +Function: padicfields +Class: basic +Section: polynomials +C-Name: padicfields0 +Prototype: GGD0,L, +Help: padicfields(p,N,{flag=0}): returns polynomials generating all + the extensions of degree N of the field of p-adic rational numbers; N is + allowed to be a 2-component vector [n,d], in which case, returns the + extensions of degree n and discriminant p^d. flag is optional, + and can be 0: default, 1: return also the ramification index, the residual + degree, the valuation of the discriminant and the number of conjugate fields, + or 2: return only the number of extensions in a fixed algebraic closure. +Doc: returns a vector of polynomials generating all the extensions of degree + $N$ of the field $\Q_{p}$ of $p$-adic rational numbers; $N$ is + allowed to be a 2-component vector $[n,d]$, in which case we return the + extensions of degree $n$ and discriminant $p^{d}$. + + The list is minimal in the sense that two different polynomials generate + nonisomorphic extensions; in particular, the number of polynomials is the + number of classes of nonisomorphic extensions. If $P$ is a polynomial in this + list, $\alpha$ is any root of $P$ and $K = \Q_{p}(\alpha)$, then $\alpha$ + is the sum of a uniformizer and a (lift of a) generator of the residue field + of $K$; in particular, the powers of $\alpha$ generate the ring of $p$-adic + integers of $K$. + + If $\fl = 1$, replace each polynomial $P$ by a vector $[P, e, f, d, c]$ + where $e$ is the ramification index, $f$ the residual degree, $d$ the + valuation of the discriminant, and $c$ the number of conjugate fields. + If $\fl = 2$, only return the \emph{number} of extensions in a fixed + algebraic closure (Krasner's formula), which is much faster. +Variant: Also available is + \fun{GEN}{padicfields}{GEN p, long n, long d, long flag}, which computes + extensions of $\Q_{p}$ of degree $n$ and discriminant $p^{d}$. + +Function: padicprec +Class: basic +Section: conversions +C-Name: gppadicprec +Prototype: GG +Help: padicprec(x,p): + return the absolute p-adic precision of object x. +Doc: returns the absolute $p$-adic precision of the object $x$; this is the + minimum precision of the components of $x$. The result is \tet{+oo} if $x$ + is an exact object (as a $p$-adic): + \bprog + ? padicprec((1 + O(2^5)) * x + (2 + O(2^4)), 2) + %1 = 4 + ? padicprec(x + 2, 2) + %2 = +oo + ? padicprec(2 + x + O(x^2), 2) + %3 = +oo + @eprog\noindent The function raises an exception if it encounters + an object incompatible with $p$-adic computations: + \bprog + ? padicprec(O(3), 2) + *** at top-level: padicprec(O(3),2) + *** ^----------------- + *** padicprec: inconsistent moduli in padicprec: 3 != 2 + + ? padicprec(1.0, 2) + *** at top-level: padicprec(1.0,2) + *** ^---------------- + *** padicprec: incorrect type in padicprec (t_REAL). + @eprog +Variant: Also available is the function \fun{long}{padicprec}{GEN x, GEN p}, + which returns \tet{LONG_MAX} if $x = 0$ and the $p$-adic precision as a + \kbd{long} integer. + +Function: parapply +Class: basic +Section: programming/parallel +C-Name: parapply +Prototype: GG +Help: parapply(f,x): parallel evaluation of f on the elements of x. +Doc: parallel evaluation of $f$ on the elements of $x$. + The function $f$ must not access global variables or variables + declared with local(), and must be free of side effects. + \bprog + parapply(factor,[2^256 + 1, 2^193 - 1]) + @eprog + factors $2^{256} + 1$ and $2^{193} - 1$ in parallel. + \bprog + { + my(E = ellinit([1,3]), V = vector(12,i,randomprime(2^200))); + parapply(p->ellcard(E,p), V) + } + @eprog + computes the order of $E(\F_{p})$ for $12$ random primes of $200$ bits. + +Function: pareval +Class: basic +Section: programming/parallel +C-Name: pareval +Prototype: G +Help: pareval(x): parallel evaluation of the elements of the vector of + closures x. +Doc: parallel evaluation of the elements of \kbd{x}, where \kbd{x} is a + vector of closures. The closures must be of arity $0$, must not access + global variables or variables declared with \kbd{local} and must be + free of side effects. + + Here is an artificial example explaining the MOV attack on the elliptic + discrete log problem (by reducing it to a standard discrete log over a + finite field): + \bprog + { + my(q = 2^30 + 3, m = 40 * q, p = 1 + m^2); \\ p, q are primes + my(E = ellinit([0,0,0,1,0] * Mod(1,p))); + my([P, Q] = ellgenerators(E)); + \\ E(F_p) ~ Z/m P + Z/m Q and the order of the + \\ Weil pairing in (Z/p)^* is m + my(F = [m,factor(m)], e = random(m), R, wR, wQ); + R = ellpow(E, Q, e); + wR = ellweilpairing(E,P,R,m); + wQ = ellweilpairing(E,P,Q,m); \\ wR = wQ^e + pareval([()->znlog(wR,wQ,F), ()->elllog(E,R,Q), ()->e]) + } + @eprog\noindent Note the use of \kbd{my} to pass "arguments" to the + functions we need to evaluate while satisfying the listed requirements: + closures of arity $0$ and no global variables (another possibility would be + to use \kbd{export}). As a result, the final three statements satisfy all + the listed requirements and are run in parallel. (Which is silly for + this computation but illustrates the use of pareval.) The function + \kbd{parfor} is more powerful but harder to use. + +Function: parfor +Class: basic +Section: programming/parallel +C-Name: parfor0 +Prototype: vV=GDGJDVDI +Help: parfor(i=a,{b},expr1,{r},{expr2}): + evaluates the expression expr1 in parallel for all i between a and b + (if b is set to +oo, the loop will not stop), resulting in as many + values; if r and expr2 are present, the expression expr2 in the + formal variables r and i is evaluated with r running through all + the different results obtained for expr1 and i takes the + corresponding argument. +Iterator: + (gen,gen,?gen,closure,?notype) (parfor, _parfor_init, _parfor_next, _parfor_stop) +Doc: evaluates in parallel the expression \kbd{expr1} in the formal + argument $i$ running from $a$ to $b$. + If $b$ is set to \kbd{+oo}, the loop runs indefinitely. + If $r$ and \kbd{expr2} are present, the expression \kbd{expr2} in the + formal variables $r$ and $i$ is evaluated with $r$ running through all + the different results obtained for \kbd{expr1} and $i$ takes the + corresponding argument. + + The computations of \kbd{expr1} are \emph{started} in increasing order + of $i$; otherwise said, the computation for $i=c$ is started after those + for $i=1, \ldots, c-1$ have been started, but before the computation for + $i=c+1$ is started. Notice that the order of \emph{completion}, that is, + the order in which the different $r$ become available, may be different; + \kbd{expr2} is evaluated sequentially on each $r$ as it appears. + + The following example computes the sum of the squares of the integers + from $1$ to $10$ by computing the squares in parallel and is equivalent + to \kbd{parsum (i=1, 10, i\^{}2)}: + \bprog + ? s=0; + ? parfor (i=1, 10, i^2, r, s=s+r) + ? s + %3 = 385 + @eprog + More precisely, apart from a potentially different order of evaluation + due to the parallelism, the line containing \kbd{parfor} is equivalent to + \bprog + ? my (r); for (i=1, 10, r=i^2; s=s+r) + @eprog + The sequentiality of the evaluation of \kbd{expr2} ensures that the + variable \kbd{s} is not modified concurrently by two different additions, + although the order in which the terms are added is nondeterministic. + + It is allowed for \kbd{expr2} to exit the loop using + \kbd{break}/\kbd{next}/\kbd{return}. If that happens for $i=c$, + then the evaluation of \kbd{expr1} and \kbd{expr2} is continued + for all values $i 7$, $k$ is the numbering of the group among all + transitive subgroups of $S_{d}$, as given in ``The transitive groups of + degree up to eleven'', G.~Butler and J.~McKay, + \emph{Communications in Algebra}, vol.~11, 1983, + pp.~863--911 (group $k$ is denoted $T_{k}$ there). And for $d \leq 7$, it was + ad hoc, so as to ensure that a given triple would denote a unique group. + Specifically, for polynomials of degree $d\leq 7$, the groups are coded as + follows, using standard notations + \smallskip + In degree 1: $S_{1}=[1,1,1]$. + \smallskip + In degree 2: $S_{2}=[2,-1,1]$. + \smallskip + In degree 3: $A_{3}=C_{3}=[3,1,1]$, $S_{3}=[6,-1,1]$. + \smallskip + In degree 4: $C_{4}=[4,-1,1]$, $V_{4}=[4,1,1]$, $D_{4}=[8,-1,1]$, $A_{4}=[12,1,1]$, + $S_{4}=[24,-1,1]$. + \smallskip + In degree 5: $C_{5}=[5,1,1]$, $D_{5}=[10,1,1]$, $M_{20}=[20,-1,1]$, + $A_{5}=[60,1,1]$, $S_{5}=[120,-1,1]$. + \smallskip + In degree 6: $C_{6}=[6,-1,1]$, $S_{3}=[6,-1,2]$, $D_{6}=[12,-1,1]$, $A_{4}=[12,1,1]$, + $G_{18}=[18,-1,1]$, $S_{4}^{-}=[24,-1,1]$, $A_{4}\times C_{2}=[24,-1,2]$, + $S_{4}^{+}=[24,1,1]$, $G_{36}^{-}=[36,-1,1]$, $G_{36}^{+}=[36,1,1]$, + $S_{4}\times C_{2}=[48,-1,1]$, $A_{5}=PSL_{2}(5)=[60,1,1]$, $G_{72}=[72,-1,1]$, + $S_{5}=PGL_{2}(5)=[120,-1,1]$, $A_{6}=[360,1,1]$, $S_{6}=[720,-1,1]$. + \smallskip + In degree 7: $C_{7}=[7,1,1]$, $D_{7}=[14,-1,1]$, $M_{21}=[21,1,1]$, + $M_{42}=[42,-1,1]$, $PSL_{2}(7)=PSL_{3}(2)=[168,1,1]$, $A_{7}=[2520,1,1]$, + $S_{7}=[5040,-1,1]$. + \smallskip + This is deprecated and obsolete, but for reasons of backward compatibility, + we cannot change this behavior yet. So you can use the default + \tet{new_galois_format} to switch to a consistent naming scheme, namely $k$ is + always the standard numbering of the group among all transitive subgroups of + $S_{n}$. If this default is in effect, the above groups will be coded as: + \smallskip + In degree 1: $S_{1}=[1,1,1]$. + \smallskip + In degree 2: $S_{2}=[2,-1,1]$. + \smallskip + In degree 3: $A_{3}=C_{3}=[3,1,1]$, $S_{3}=[6,-1,2]$. + \smallskip + In degree 4: $C_{4}=[4,-1,1]$, $V_{4}=[4,1,2]$, $D_{4}=[8,-1,3]$, $A_{4}=[12,1,4]$, + $S_{4}=[24,-1,5]$. + \smallskip + In degree 5: $C_{5}=[5,1,1]$, $D_{5}=[10,1,2]$, $M_{20}=[20,-1,3]$, + $A_{5}=[60,1,4]$, $S_{5}=[120,-1,5]$. + \smallskip + In degree 6: $C_{6}=[6,-1,1]$, $S_{3}=[6,-1,2]$, $D_{6}=[12,-1,3]$, $A_{4}=[12,1,4]$, + $G_{18}=[18,-1,5]$, $A_{4}\times C_{2}=[24,-1,6]$, $S_{4}^{+}=[24,1,7]$, + $S_{4}^{-}=[24,-1,8]$, $G_{36}^{-}=[36,-1,9]$, $G_{36}^{+}=[36,1,10]$, + $S_{4}\times C_{2}=[48,-1,11]$, $A_{5}=PSL_{2}(5)=[60,1,12]$, $G_{72}=[72,-1,13]$, + $S_{5}=PGL_{2}(5)=[120,-1,14]$, $A_{6}=[360,1,15]$, $S_{6}=[720,-1,16]$. + \smallskip + In degree 7: $C_{7}=[7,1,1]$, $D_{7}=[14,-1,2]$, $M_{21}=[21,1,3]$, + $M_{42}=[42,-1,4]$, $PSL_{2}(7)=PSL_{3}(2)=[168,1,5]$, $A_{7}=[2520,1,6]$, + $S_{7}=[5040,-1,7]$. + \smallskip + + \misctitle{Warning} The method used is that of resolvent polynomials and is + sensitive to the current precision. The precision is updated internally but, + in very rare cases, a wrong result may be returned if the initial precision + was not sufficient. +Variant: To enable the new format in library mode, + set the global variable \tet{new_galois_format} to $1$. + +Function: polgraeffe +Class: basic +Section: polynomials +C-Name: polgraeffe +Prototype: G +Help: polgraeffe(f): returns the Graeffe transform g of f, such that + g(x^2) = f(x)f(-x). +Doc: returns the \idx{Graeffe} transform $g$ of $f$, such that $g(x^{2}) = f(x) + f(-x)$. + +Function: polhensellift +Class: basic +Section: polynomials +C-Name: polhensellift +Prototype: GGGL +Help: polhensellift(A,B,p,e): lift the factorization B of A modulo p to a + factorization modulo p^e using Hensel lift. The factors in B must be + pairwise relatively prime modulo p. +Doc: given a prime $p$, an integral polynomial $A$ whose leading coefficient + is a $p$-unit, a vector $B$ of integral polynomials that are monic and + pairwise relatively prime modulo $p$, and whose product is congruent to + $A/\text{lc}(A)$ modulo $p$, lift the elements of $B$ to polynomials whose + product is congruent to $A$ modulo $p^{e}$. + + More generally, if $T$ is an integral polynomial irreducible mod $p$, and + $B$ is a factorization of $A$ over the finite field $\F_{p}[t]/(T)$, you can + lift it to $\Z_{p}[t]/(T, p^{e})$ by replacing the $p$ argument with $[p,T]$: + \bprog + ? { T = t^3 - 2; p = 7; A = x^2 + t + 1; + B = [x + (3*t^2 + t + 1), x + (4*t^2 + 6*t + 6)]; + r = polhensellift(A, B, [p, T], 6) } + %1 = [x + (20191*t^2 + 50604*t + 75783), x + (97458*t^2 + 67045*t + 41866)] + ? liftall( r[1] * r[2] * Mod(Mod(1,p^6),T) ) + %2 = x^2 + (t + 1) + @eprog + +Function: polhermite +Class: basic +Section: polynomials +C-Name: polhermite_eval0 +Prototype: LDGD0,L, +Help: polhermite(n,{a='x},{flag=0}): Hermite polynomial H(n,v) of degree n, + evaluated at a. If flag is nonzero, return [H_{n-1}(a), H_n(a)]. +Description: + (small,?var):gen polhermite($1,$2) + (small,gen):gen polhermite_eval($1,$2) +Doc: $n^{\text{th}}$ \idx{Hermite} polynomial $H_{n}$ evaluated at $a$ + (\kbd{'x} by default), i.e. + $$ H_{n}(x) = (-1)^{n}\*e^{x^{2}} \dfrac{d^{n}}{dx^{n}}e^{-x^{2}}.$$ + If \fl\ is nonzero and $n > 0$, return $[H_{n-1}(a), H_{n}(a)]$. + \bprog + ? polhermite(5) + %1 = 32*x^5 - 160*x^3 + 120*x + ? polhermite(5, -2) \\ H_5(-2) + %2 = 16 + ? polhermite(5,,1) + %3 = [16*x^4 - 48*x^2 + 12, 32*x^5 - 160*x^3 + 120*x] + ? polhermite(5,-2,1) + %4 = [76, 16] + @eprog +Variant: The variant \fun{GEN}{polhermite}{long n, long v} returns the $n$-th + Hermite polynomial in variable $v$. To obtain $H_{n}(a)$, + use \fun{GEN}{polhermite_eval}{long n, GEN a}. + +Function: polinterpolate +Class: basic +Section: polynomials +C-Name: polint +Prototype: GDGDGD& +Help: polinterpolate(X,{Y},{t = 'x},{&e}): polynomial interpolation at t + according to data vectors X, Y, i.e., given P of minimal degree + such that P(X[i]) = Y[i] for all i, return P(t). If Y is omitted, + take P such that P(i) = X[i]. If present and t is numeric, e will contain an + error estimate on the returned value (Neville's algorithm). +Doc: given the data vectors $X$ and $Y$ of the same length $n$ + ($X$ containing the $x$-coordinates, and $Y$ the corresponding + $y$-coordinates), this function finds the \idx{interpolating polynomial} + $P$ of minimal degree passing through these points and evaluates it at~$t$. + If $Y$ is omitted, the polynomial $P$ interpolates the $(i,X[i])$. + + \bprog + ? v = [1, 2, 4, 8, 11, 13]; + ? P = polinterpolate(v) \\ formal interpolation + %1 = 7/120*x^5 - 25/24*x^4 + 163/24*x^3 - 467/24*x^2 + 513/20*x - 11 + ? [ subst(P,'x,a) | a <- [1..6] ] + %2 = [1, 2, 4, 8, 11, 13] + ? polinterpolate(v,, 10) \\ evaluate at 10 + %3 = 508 + ? subst(P, x, 10) + %4 = 508 + + ? P = polinterpolate([1,2,4], [9,8,7]) + %5 = 1/6*x^2 - 3/2*x + 31/3 + ? [subst(P, 'x, a) | a <- [1,2,4]] + %6 = [9, 8, 7] + ? P = polinterpolate([1,2,4], [9,8,7], 0) + %7 = 31/3 + @eprog\noindent If the goal is to extrapolate a function at a unique point, + it is more efficient to use the $t$ argument rather than interpolate formally + then evaluate: + \bprog + ? x0 = 1.5; + ? v = vector(20, i,random([-10,10])); + ? for(i=1,10^3, subst(polinterpolate(v),'x, x0)) + time = 352 ms. + ? for(i=1,10^3, polinterpolate(v,,x0)) + time = 111 ms. + + ? v = vector(40, i,random([-10,10])); + ? for(i=1,10^3, subst(polinterpolate(v), 'x, x0)) + time = 3,035 ms. + ? for(i=1,10^3, polinterpolate(v,, x0)) + time = 436 ms. + @eprog\noindent The threshold depends on the base field. Over small prime + finite fields, interpolating formally first is more efficient + \bprog + ? bench(p, N, T = 10^3) = + { my (v = vector(N, i, random(Mod(0,p)))); + my (x0 = Mod(3, p), t1, t2); + gettime(); + for(i=1, T, subst(polinterpolate(v), 'x, x0)); + t1 = gettime(); + for(i=1, T, polinterpolate(v,, x0)); + t2 = gettime(); [t1, t2]; + } + ? p = 101; + ? bench(p, 4, 10^4) \\ both methods are equivalent + %3 = [39, 40] + ? bench(p, 40) \\ with 40 points formal is much faster + %4 = [45, 355] + @eprog\noindent As the cardinality increases, formal interpolation requires + more points to become interesting: + \bprog + ? p = nextprime(2^128); + ? bench(p, 4) \\ formal is slower + %3 = [16, 9] + ? bench(p, 10) \\ formal has become faster + %4 = [61, 70] + ? bench(p, 100) \\ formal is much faster + %5 = [1682, 9081] + + ? p = nextprime(10^500); + ? bench(p, 4) \\ formal is slower + %7 = [72, 354] + ? bench(p, 20) \\ formal is still slower + %8 = [1287, 962] + ? bench(p, 40) \\ formal has become faster + %9 = [3717, 4227] + ? bench(p, 100) \\ faster but relatively less impressive + %10 = [16237, 32335] + @eprog + + If $t$ is a complex numeric value and $e$ is present, $e$ will contain an + error estimate on the returned value. More precisely, let $P$ be the + interpolation polynomial on the given $n$ points; there exist a subset + of $n-1$ points and $Q$ the attached interpolation polynomial + such that $e = \kbd{exponent}(P(t) - Q(t))$ (Neville's algorithm). + \bprog + ? f(x) = 1 / (1 + 25*x^2); + ? x0 = 975/1000; + ? test(X) = + { my (P, e); + P = polinterpolate(X, [f(x) | x <- X], x0, &e); + [ exponent(P - f(x0)), e ]; + } + \\ equidistant nodes vs. Chebyshev nodes + ? test( [-10..10] / 10 ) + %4 = [6, 5] + ? test( polrootsreal(polchebyshev(21)) ) + %5 = [-15, -10] + + ? test( [-100..100] / 100 ) + %7 = [93, 97] \\ P(x0) is way different from f(x0) + ? test( polrootsreal(polchebyshev(201)) ) + %8 = [-60, -55] + @eprog\noindent This is an example of Runge's phenomenon: increasing the + number of equidistant nodes makes extrapolation much worse. Note that the + error estimate is not a guaranteed upper bound (cf \%4), but is reasonably + tight in practice. + + \misctitle{Numerical stability} The interpolation is performed in + a numerically stable way using $\prod_{j\neq i} (X[i] - X[j])$ instead of + $Q'(X[i])$ with $Q = \prod_{i} (x - X[i])$. Centering the interpolation + points $X[i]$ around $0$, thereby reconstructing $P(x - m)$, for a suitable + $m$ will further reduce the numerical error. + +Function: polisclass +Class: basic +Section: polynomials +C-Name: polisclass +Prototype: lG +Help: polisclass(P): P being a monic irreducible polynomial with integer + coefficients, return 0 if P is not a class polynomial for the j-invariant, + otherwise return the discriminant D<0 such that P=polclass(D). +Doc: $P$ being a monic irreducible polynomial with integer coefficients, + return $0$ if $P$ is not a class polynomial for the $j$-invariant, + otherwise return the discriminant $D<0$ such that \kbd{P=polclass(D)}. + \bprog + ? polisclass(polclass(-47)) + %1 = -47 + ? polisclass(x^5+x+1) + %2 = 0 + ? apply(polisclass,factor(poldisc(polmodular(5)))[,1]) + %3 = [-16,-4,-3,-11,-19,-64,-36,-24,-51,-91,-99,-96,-84]~ + @eprog + +Function: poliscyclo +Class: basic +Section: polynomials +C-Name: poliscyclo +Prototype: lG +Help: poliscyclo(f): returns 0 if f is not a cyclotomic polynomial, and n + > 0 if f = Phi_n, the n-th cyclotomic polynomial. +Doc: returns 0 if $f$ is not a cyclotomic polynomial, and $n > 0$ if $f = + \Phi_{n}$, the $n$-th cyclotomic polynomial. + \bprog + ? poliscyclo(x^4-x^2+1) + %1 = 12 + ? polcyclo(12) + %2 = x^4 - x^2 + 1 + ? poliscyclo(x^4-x^2-1) + %3 = 0 + @eprog + +Function: poliscycloprod +Class: basic +Section: polynomials +C-Name: poliscycloprod +Prototype: lG +Help: poliscycloprod(f): returns 1 if f is a product of cyclotomic + polynonials, and 0 otherwise. +Doc: returns 1 if $f$ is a product of cyclotomic polynomial, and $0$ + otherwise. + \bprog + ? f = x^6+x^5-x^3+x+1; + ? poliscycloprod(f) + %2 = 1 + ? factor(f) + %3 = + [ x^2 + x + 1 1] + + [x^4 - x^2 + 1 1] + ? [ poliscyclo(T) | T <- %[,1] ] + %4 = [3, 12] + ? polcyclo(3) * polcyclo(12) + %5 = x^6 + x^5 - x^3 + x + 1 + @eprog + +Function: polisirreducible +Class: basic +Section: polynomials +C-Name: polisirreducible +Prototype: lG +Help: polisirreducible(pol): true(1) if pol is an irreducible nonconstant + polynomial, false(0) if pol is reducible or constant. +Doc: \var{pol} being a polynomial (univariate in the present version \vers), + returns 1 if \var{pol} is nonconstant and irreducible, 0 otherwise. + Irreducibility is checked over the smallest base field over which \var{pol} + seems to be defined. + +Function: pollaguerre +Class: basic +Section: polynomials +C-Name: pollaguerre_eval0 +Prototype: LDGDGD0,L, +Help: pollaguerre(n,{a=0},{b='x},{flag=0}): Laguerre polynomial of degree n + and parameter a evaluated at b. If flag is 1, return [L^{(a)_{n-1}(b), + L^{(a)}_n(b)]. +Doc: $n^{\text{th}}$ \idx{Laguerre polynomial} $L^{(a)}_{n}$ of degree $n$ and + parameter $a$ evaluated at $b$ (\kbd{'x} by default), i.e. + $$ L_{n}^{(a)}(x) = + \dfrac{x^{-a}e^{x}}{n!} \dfrac{d^{n}}{dx^{n}}\big(e^{-x}x^{n+a}\big).$$ + If \fl\ is $1$, return $[L^{(a)}_{n-1}(b), L_{n}^{(a)}(b)]$. +Variant: To obtain the $n$-th Laguerre polynomial in variable $v$, + use \fun{GEN}{pollaguerre}{long n, GEN a, GEN b, long v}. To obtain + $L^{(a)}_{n}(b)$, use \fun{GEN}{pollaguerre_eval}{long n, GEN a, GEN b}. + +Function: pollead +Class: basic +Section: polynomials +C-Name: pollead +Prototype: GDn +Help: pollead(x,{v}): leading coefficient of polynomial or series x, or x + itself if x is a scalar. Error otherwise. With respect to the main variable + of x if v is omitted, with respect to the variable v otherwise. +Description: + (pol):gen:copy leading_coeff($1) + (gen):gen pollead($1, -1) + (gen, var):gen pollead($1, $2) +Doc: leading coefficient of the polynomial or power series $x$. This is + computed with respect to the main variable of $x$ if $v$ is omitted, with + respect to the variable $v$ otherwise. + +Function: pollegendre +Class: basic +Section: polynomials +C-Name: pollegendre_eval0 +Prototype: LDGD0,L, +Help: pollegendre(n,{a='x},{flag=0}): legendre polynomial of degree n evaluated + at a. If flag is 1, return [P_{n-1}(a), P_n(a)]. +Description: + (small,?var):gen pollegendre($1,$2) + (small,gen):gen pollegendre_eval($1,$2) +Doc: $n^{\text{th}}$ \idx{Legendre polynomial} $P_{n}$ evaluated at $a$ + (\kbd{'x} by default), where + $$P_{n}(x) = \dfrac{1}{2^{n} n!} \dfrac{d^{n}}{dx^{n}}(x^{2}-1)^{n}\;.$$ + If \fl\ is 1, return $[P_{n-1}(a), P_{n}(a)]$. +Variant: To obtain the $n$-th Legendre polynomial $P_{n}$ in variable $v$, + use \fun{GEN}{pollegendre}{long n, long v}. To obtain $P_{n}(a)$, + use \fun{GEN}{pollegendre_eval}{long n, GEN a}. + +Function: polmodular +Class: basic +Section: polynomials +C-Name: polmodular +Prototype: LD0,L,DGDnD0,L, +Help: polmodular(L,{inv=0},{x='x},{y='y},{derivs=0}): + return the modular polynomial of level L and invariant inv. +Doc: Return the modular polynomial of prime level $L$ in variables $x$ and $y$ + for the modular function specified by \kbd{inv}. If \kbd{inv} is 0 (the + default), use the modular $j$ function, if \kbd{inv} is 1 use the + Weber-$f$ function, and if \kbd{inv} is 5 use $\gamma_{2} = + \sqrt[3]{j}$. + See \kbd{polclass} for the full list of invariants. + If $x$ is given as \kbd{Mod(j, p)} or an element $j$ of + a finite field (as a \typ{FFELT}), then return the modular polynomial of + level $L$ evaluated at $j$. If $j$ is from a finite field and + \kbd{derivs} is nonzero, then return a triple where the + last two elements are the first and second derivatives of the modular + polynomial evaluated at $j$. + \bprog + ? polmodular(3) + %1 = x^4 + (-y^3 + 2232*y^2 - 1069956*y + 36864000)*x^3 + ... + ? polmodular(7, 1, , 'J) + %2 = x^8 - J^7*x^7 + 7*J^4*x^4 - 8*J*x + J^8 + ? polmodular(7, 5, 7*ffgen(19)^0, 'j) + %3 = j^8 + 4*j^7 + 4*j^6 + 8*j^5 + j^4 + 12*j^2 + 18*j + 18 + ? polmodular(7, 5, Mod(7,19), 'j) + %4 = Mod(1, 19)*j^8 + Mod(4, 19)*j^7 + Mod(4, 19)*j^6 + ... + + ? u = ffgen(5)^0; T = polmodular(3,0,,'j)*u; + ? polmodular(3, 0, u,'j,1) + %6 = [j^4 + 3*j^2 + 4*j + 1, 3*j^2 + 2*j + 4, 3*j^3 + 4*j^2 + 4*j + 2] + ? subst(T,x,u) + %7 = j^4 + 3*j^2 + 4*j + 1 + ? subst(T',x,u) + %8 = 3*j^2 + 2*j + 4 + ? subst(T'',x,u) + %9 = 3*j^3 + 4*j^2 + 4*j + 2 + @eprog + +Function: polrecip +Class: basic +Section: polynomials +C-Name: polrecip +Prototype: G +Help: polrecip(pol): reciprocal polynomial of pol. +Doc: reciprocal polynomial of \var{pol} with respect to its main variable, + i.e.~the coefficients of the result are in reverse order; \var{pol} must be + a polynomial. + \bprog + ? polrecip(x^2 + 2*x + 3) + %1 = 3*x^2 + 2*x + 1 + ? polrecip(2*x + y) + %2 = y*x + 2 + @eprog + +Function: polred +Class: basic +Section: number_fields +C-Name: polred0 +Prototype: GD0,L,DG +Obsolete: 2013-03-27 +Help: polred(T,{flag=0}): deprecated, use polredbest. Reduction of the + polynomial T (gives minimal polynomials only). The following binary digits of + (optional) flag are significant 1: partial reduction, 2: gives also elements. +Doc: This function is \emph{deprecated}, use \tet{polredbest} instead. + Finds polynomials with reasonably small coefficients defining subfields of + the number field defined by $T$. One of the polynomials always defines $\Q$ + (hence has degree $1$), and another always defines the same number field + as $T$ if $T$ is irreducible. + + All $T$ accepted by \tet{nfinit} are also allowed here; + in particular, the format \kbd{[T, listP]} is recommended, e.g. with + $\kbd{listP} = 10^{5}$ or a vector containing all ramified primes. Otherwise, + the maximal order of $\Q[x]/(T)$ must be computed. + + The following binary digits of $\fl$ are significant: + + 1: Possibly use a suborder of the maximal order. The + primes dividing the index of the order chosen are larger than + \tet{primelimit} or divide integers stored in the \tet{addprimes} table. + This flag is \emph{deprecated}, the \kbd{[T, listP]} format is more + flexible. + + 2: gives also elements. The result is a two-column matrix, the first column + giving primitive elements defining these subfields, the second giving the + corresponding minimal polynomials. + \bprog + ? M = polred(x^4 + 8, 2) + %1 = + [ 1 x - 1] + + [ 1/2*x^2 + 1 x^2 - 2*x + 3] + + [-1/2*x^2 + 1 x^2 - 2*x + 3] + + [ 1/2*x^2 x^2 + 2] + + [ 1/4*x^3 x^4 + 2] + ? minpoly(Mod(M[4,1], x^4+8)) + %2 = x^2 + 2 + @eprog + + \synt{polred}{GEN T} ($\fl = 0$). Also available is + \fun{GEN}{polred2}{GEN T} ($\fl = 2$). The function \kbd{polred0} is + deprecated, provided for backward compatibility. + +Function: polredabs +Class: basic +Section: number_fields +C-Name: polredabs0 +Prototype: GD0,L, +Help: polredabs(T,{flag=0}): a smallest generating polynomial of the number + field for the T2 norm on the roots, with smallest index for the minimal T2 + norm. flag is optional, whose binary digit mean 1: give the element whose + characteristic polynomial is the given polynomial. 4: give all polynomials + of minimal T2 norm (give only one of P(x) and P(-x)). +Doc: returns a canonical defining polynomial $P$ for the number field + $\Q[X]/(T)$ defined by $T$, such that the sum of the squares of the modulus + of the roots (i.e.~the $T_{2}$-norm) is minimal. Different $T$ defining + isomorphic number fields will yield the same $P$. All $T$ accepted by + \tet{nfinit} are also allowed here, e.g. nonmonic polynomials, or pairs + \kbd{[T, listP]} specifying that a nonmaximal order may be used. For + convenience, any number field structure (\var{nf}, \var{bnf},\dots) can also + be used instead of $T$. + \bprog + ? polredabs(x^2 + 16) + %1 = x^2 + 1 + ? K = bnfinit(x^2 + 16); polredabs(K) + %2 = x^2 + 1 + @eprog + + \misctitle{Warning 1} Using a \typ{POL} $T$ requires computing + and fully factoring the discriminant $d_{K}$ of the maximal order which may be + very hard. You can use the format \kbd{[T, listP]}, where \kbd{listP} + encodes a list of known coprime divisors of $\disc(T)$ (see \kbd{??nfbasis}), + to help the routine, thereby replacing this part of the algorithm by a + polynomial time computation But this may only compute a suborder of the + maximal order, when the divisors are not squarefree or do not include all + primes dividing $d_{K}$. The routine attempts to certify the result + independently of this order computation as per \tet{nfcertify}: we try to + prove that the computed order is maximal. If the certification fails, + the routine then fully factors the integers returned by \kbd{nfcertify}. + You can also use \tet{polredbest} to avoid this factorization step; in this + case, the result is small but no longer canonical. + + \misctitle{Warning 2} Apart from the factorization of the discriminant of + $T$, this routine runs in polynomial time for a \emph{fixed} degree. + But the complexity is exponential in the degree: this routine + may be exceedingly slow when the number field has many subfields, hence a + lot of elements of small $T_{2}$-norm. If you do not need a canonical + polynomial, the function \tet{polredbest} is in general much faster (it runs + in polynomial time), and tends to return polynomials with smaller + discriminants. + + The binary digits of $\fl$ mean + + 1: outputs a two-component row vector $[P,a]$, where $P$ is the default + output and \kbd{Mod(a, P)} is a root of the original $T$. + + 4: gives \emph{all} polynomials of minimal $T_{2}$ norm; of the two polynomials + $P(x)$ and $\pm P(-x)$, only one is given. + + 16: (OBSOLETE) Possibly use a suborder of the maximal order, \emph{without} + attempting to certify the result as in Warning 1. This makes \kbd{polredabs} + behave like \kbd{polredbest}. Just use the latter. + + \bprog + ? T = x^16 - 136*x^14 + 6476*x^12 - 141912*x^10 + 1513334*x^8 \ + - 7453176*x^6 + 13950764*x^4 - 5596840*x^2 + 46225 + ? T1 = polredabs(T); T2 = polredbest(T); + ? [ norml2(polroots(T1)), norml2(polroots(T2)) ] + %3 = [88.0000000, 120.000000] + ? [ sizedigit(poldisc(T1)), sizedigit(poldisc(T2)) ] + %4 = [75, 67] + @eprog + + The precise definition of the output of \tet{polredabs} is as follows. + + \item Consider the finite list of characteristic polynomials of primitive + elements of~$K$ that are in~$\Z_{K}$ and minimal for the~$T_{2}$ norm; + now remove from the list the polynomials whose discriminant do not have + minimal absolute value. Note that this condition is restricted to the + original list of polynomials with minimal $T_{2}$ norm and does not imply that + the defining polynomial for the field with smallest discriminant belongs to + the list ! + + \item To a polynomial $P(x) = x^{n} + \dots + a_{n} \in \R[x]$ we attach + the sequence $S(P)$ given by $|a_{1}|, a_{1}, \dots, |a_{n}|, a_{n}$. + Order the polynomials $P$ by the lexicographic order on the coefficient + vectors $S(P)$. Then the output of \tet{polredabs} is the smallest + polynomial in the above list for that order. In other words, the monic + polynomial which is lexicographically smallest with respect to the absolute + values of coefficients, favouring negative coefficients to break ties, i.e. + choosing $x^{3}-2$ rather than $x^{3}+2$. +Variant: Instead of the above hardcoded numerical flags, one should use an + or-ed combination of + + \item \tet{nf_PARTIALFACT} (OBSOLETE): possibly use a suborder of the maximal + order, \emph{without} attempting to certify the result. + + \item \tet{nf_ORIG}: return $[P, a]$, where \kbd{Mod(a, P)} is a root of $T$. + + \item \tet{nf_RAW}: return $[P, b]$, where \kbd{Mod(b, T)} is a root of $P$. + The algebraic integer $b$ is the raw result produced by the small vectors + enumeration in the maximal order; $P$ was computed as the characteristic + polynomial of \kbd{Mod(b, T)}. \kbd{Mod(a, P)} as in \tet{nf_ORIG} + is obtained with \tet{modreverse}. + + \item \tet{nf_ADDZK}: if $r$ is the result produced with some of the above + flags (of the form $P$ or $[P,c]$), return \kbd{[r,zk]}, where \kbd{zk} is a + $\Z$-basis for the maximal order of $\Q[X]/(P)$. + + \item \tet{nf_ALL}: return a vector of results of the above form, for all + polynomials of minimal $T_{2}$-norm. + +Function: polredbest +Class: basic +Section: number_fields +C-Name: polredbest +Prototype: GD0,L, +Help: polredbest(T,{flag=0}): reduction of the polynomial T (gives minimal + polynomials only). If flag=1, gives also elements. +Doc: finds a polynomial with reasonably + small coefficients defining the same number field as $T$. + All $T$ accepted by \tet{nfinit} are also allowed here (e.g. nonmonic + polynomials, \kbd{nf}, \kbd{bnf}, \kbd{[T,Z\_K\_basis]}). Contrary to + \tet{polredabs}, this routine runs in polynomial time, but it offers no + guarantee as to the minimality of its result. + + This routine computes an LLL-reduced basis for an order in $\Q[X]/(T)$, then + examines small linear combinations of the basis vectors, computing their + characteristic polynomials. It returns the \emph{separable} polynomial $P$ of + smallest discriminant, the one with lexicographically smallest + \kbd{abs(Vec(P))} in case of ties. This is a good candidate for subsequent + number field computations since it guarantees that the denominators of + algebraic integers, when expressed in the power basis, are reasonably small. + With no claim of minimality, though. + + It can happen that iterating this functions yields better and better + polynomials, until it stabilizes: + \bprog + ? \p5 + ? P = X^12+8*X^8-50*X^6+16*X^4-3069*X^2+625; + ? poldisc(P)*1. + %2 = 1.2622 E55 + ? P = polredbest(P); + ? poldisc(P)*1. + %4 = 2.9012 E51 + ? P = polredbest(P); + ? poldisc(P)*1. + %6 = 8.8704 E44 + @eprog\noindent In this example, the initial polynomial $P$ is the one + returned by \tet{polredabs}, and the last one is stable. + + If $\fl = 1$: outputs a two-component row vector $[P,a]$, where $P$ is the + default output and \kbd{a}, a \typ{POLMOD} modulo~\kbd{P}, is a root of the + original $T$. + \bprog + ? [P,a] = polredbest(x^4 + 8, 1) + %1 = [x^4 + 2, Mod(x^3, x^4 + 2)] + ? charpoly(a) + %2 = x^4 + 8 + @eprog\noindent In particular, the map $\Q[x]/(T) \to \Q[x]/(P)$, + $x\mapsto \kbd{a}$ defines an isomorphism of number fields, which can + be computed as + \bprog + subst(lift(Q), 'x, a) + @eprog\noindent if $Q$ is a \typ{POLMOD} modulo $T$; \kbd{b = modreverse(a)} + returns a \typ{POLMOD} giving the inverse of the above map (which should be + useless since $\Q[x]/(P)$ is a priori a better representation for the number + field and its elements). + +Function: polredord +Class: basic +Section: number_fields +C-Name: polredord +Prototype: G +Obsolete: 2008-07-20 +Help: polredord(x): this function is obsolete, use polredbest. +Doc: This function is obsolete, use polredbest. + +Function: polresultant +Class: basic +Section: polynomials +C-Name: polresultant0 +Prototype: GGDnD0,L, +Help: polresultant(x,y,{v},{flag=0}): resultant of the polynomials x and y, + with respect to the main variables of x and y if v is omitted, with respect + to the variable v otherwise. flag is optional, and can be 0: default, + uses either the subresultant algorithm, a modular algorithm or Sylvester's + matrix, depending on the inputs; 1 uses Sylvester's matrix (should always be + slower than the default). +Doc: resultant of the two + polynomials $x$ and $y$ with exact entries, with respect to the main + variables of $x$ and $y$ if $v$ is omitted, with respect to the variable $v$ + otherwise. The algorithm assumes the base ring is a domain. If you also need + the $u$ and $v$ such that $x*u + y*v = \text{Res}(x,y)$, use the + \tet{polresultantext} function. + + If $\fl=0$ (default), uses the algorithm best suited to the inputs, + either the \idx{subresultant algorithm} (Lazard/Ducos variant, generic case), + a modular algorithm (inputs in $\Q[X]$) or Sylvester's matrix (inexact + inputs). + + If $\fl=1$, uses the determinant of Sylvester's matrix instead; this should + always be slower than the default. + + If $x$ or $y$ are multivariate with a huge \emph{polynomial} content, it + is advisable to remove it before calling this function. Compare: + \bprog + ? a = polcyclo(7) * ((t+1)/(t+2))^100; + ? b = polcyclo(11)* ((t+2)/(t+3))^100); + ? polresultant(a,b); + time = 3,833 ms. + ? ca = content(a); cb = content(b); \ + polresultant(a/ca,b/cb)*ca^poldegree(b)*cb*poldegree(a); \\ instantaneous + @eprog\noindent The function only removes rational denominators and does + not compute automatically the content because it is generically small and + potentially \emph{very} expensive (e.g. in multivariate contexts). + The choice is yours, depending on your application. + +Function: polresultantext +Class: basic +Section: polynomials +C-Name: polresultantext0 +Prototype: GGDn +Help: polresultantext(A,B,{v}): return [U,V,R] such that + R=polresultant(A,B,v) and U*A+V*B = R, where A and B are polynomials. +Doc: finds polynomials $U$ and $V$ such that $A*U + B*V = R$, where $R$ is + the resultant of $U$ and $V$ with respect to the main variables of $A$ and + $B$ if $v$ is omitted, and with respect to $v$ otherwise. Returns the row + vector $[U,V,R]$. The algorithm used (subresultant) assumes that the base + ring is a domain. + \bprog + ? A = x*y; B = (x+y)^2; + ? [U,V,R] = polresultantext(A, B) + %2 = [-y*x - 2*y^2, y^2, y^4] + ? A*U + B*V + %3 = y^4 + ? [U,V,R] = polresultantext(A, B, y) + %4 = [-2*x^2 - y*x, x^2, x^4] + ? A*U+B*V + %5 = x^4 + @eprog +Variant: Also available is + \fun{GEN}{polresultantext}{GEN x, GEN y}. + +Function: polroots +Class: basic +Section: polynomials +C-Name: roots +Prototype: Gp +Help: polroots(T): complex roots of the polynomial T using + Schonhage's method, as modified by Gourdon. +Description: + (gen):vec:prec roots($1, $prec) +Doc: complex roots of the polynomial $T$, given as a column vector where each + root is repeated according to its multiplicity and given as floating point + complex numbers at the current \kbd{realprecision}: + \bprog + ? polroots(x^2) + %1 = [0.E-38 + 0.E-38*I, 0.E-38 + 0.E-38*I]~ + + ? polroots(x^3+1) + %2 = [-1.00... + 0.E-38*I, 0.50... - 0.866...*I, 0.50... + 0.866...*I]~ + @eprog + + The algorithm used is a modification of Sch\"onhage\sidx{Sch\"onage}'s + root-finding algorithm, due to and originally implemented by Gourdon. + It runs in polynomial time in $\text{deg}(T)$ and the precision. + If furthermore $T$ has rational coefficients, roots are guaranteed to the + required relative accuracy. If the input polynomial $T$ is exact, then + the ordering of the roots does not depend on the precision: they are ordered + by increasing $|\Im z|$, then by increasing $\Re z$; in case of tie + (conjugates), the root with negative imaginary part comes first. + +Function: polrootsbound +Class: basic +Section: polynomials +C-Name: polrootsbound +Prototype: GDG +Help: polrootsbound(T,{tau=0.01}): return a sharp upper bound for the + modulus of the largest complex root of the polynomial T with relative error + tau. +Doc: return a sharp upper bound $B$ for the modulus of + the largest complex root of the polynomial $T$ with complex coefficients + with relative error $\tau$. More precisely, we have $|z| \leq B$ for all roots + and there exist one root such that $|z_{0}| \geq B \exp(-2\tau)$. Much faster + than either polroots or polrootsreal. + \bprog + ? T=poltchebi(500); + ? vecmax(abs(polroots(T))) + time = 5,706 ms. + %2 = 0.99999506520185816611184481744870013191 + ? vecmax(abs(polrootsreal(T))) + time = 1,972 ms. + %3 = 0.99999506520185816611184481744870013191 + ? polrootsbound(T) + time = 217 ms. + %4 = 1.0098792554165905155 + ? polrootsbound(T, log(2)/2) \\ allow a factor 2, much faster + time = 51 ms. + %5 = 1.4065759938190154354 + ? polrootsbound(T, 1e-4) + time = 504 ms. + %6 = 1.0000920717983847741 + ? polrootsbound(T, 1e-6) + time = 810 ms. + %7 = 0.9999960628901692905 + ? polrootsbound(T, 1e-10) + time = 1,351 ms. + %8 = 0.9999950652993869760 + @eprog + +Function: polrootsff +Class: basic +Section: polynomials +C-Name: polrootsff +Prototype: GDGDG +Obsolete: 2018-03-11 +Help: polrootsff(x,{p},{a}): obsolete, use polrootsmod. +Doc: obsolete, kept for backward compatibility: use polrootsmod. + +Function: polrootsmod +Class: basic +Section: polynomials +C-Name: polrootsmod +Prototype: GDG +Help: polrootsmod(f,{D}): roots of the polynomial f over the finite field + defined by the domain D. +Doc: vector of roots of the polynomial $f$ over the finite field defined + by the domain $D$ as follows: + + \item $D = p$ a prime: factor over $\F_{p}$; + + \item $D = [T,p]$ for a prime $p$ and $T(y)$ an irreducible polynomial over + $\F_{p}$: factor over $\F_{p}[y]/(T)$ (as usual the main variable of $T$ + must have lower priority than the main variable of $f$); + + \item $D$ a \typ{FFELT}: factor over the attached field; + + \item $D$ omitted: factor over the field of definition of $f$, which + must be a finite field. + + \noindent Multiple roots are \emph{not} repeated. + \bprog + ? polrootsmod(x^2-1,2) + %1 = [Mod(1, 2)]~ + ? polrootsmod(x^2+1,3) + %2 = []~ + ? polrootsmod(x^2+1, [y^2+1,3]) + %3 = [Mod(Mod(1, 3)*y, Mod(1, 3)*y^2 + Mod(1, 3)), + Mod(Mod(2, 3)*y, Mod(1, 3)*y^2 + Mod(1, 3))]~ + ? polrootsmod(x^2 + Mod(1,3)) + %4 = []~ + ? liftall( polrootsmod(x^2 + Mod(Mod(1,3),y^2+1)) ) + %5 = [y, 2*y]~ + ? t = ffgen(y^2+Mod(1,3)); polrootsmod(x^2 + t^0) + %6 = [y, 2*y]~ + @eprog + +Function: polrootspadic +Class: basic +Section: polynomials +C-Name: polrootspadic +Prototype: GGL +Help: polrootspadic(f,p,r): p-adic roots of the polynomial f to precision r. +Doc: vector of $p$-adic roots of the polynomial \var{pol}, given to + $p$-adic precision $r$; the integer $p$ is assumed to be a prime. + Multiple roots are + \emph{not} repeated. Note that this is not the same as the roots in + $\Z/p^{r}\Z$, rather it gives approximations in $\Z/p^{r}\Z$ of the true roots + living in $\Q_{p}$: + \bprog + ? polrootspadic(x^3 - x^2 + 64, 2, 4) + %1 = [2^3 + O(2^4), 2^3 + O(2^4), 1 + O(2^4)]~ + ? polrootspadic(x^3 - x^2 + 64, 2, 5) + %2 = [2^3 + O(2^5), 2^3 + 2^4 + O(2^5), 1 + O(2^5)]~ + @eprog\noindent As the second commands show, the first two roots \emph{are} + distinct in $\Q_{p}$, even though they are equal modulo $2^{4}$. + + More generally, if $T$ is an integral polynomial irreducible + mod $p$ and $f$ has coefficients in $\Q[t]/(T)$, the argument $p$ + may be replaced by the vector $[T,p]$; we then return the roots of $f$ in + the unramified extension $\Q_{p}[t]/(T)$. + \bprog + ? polrootspadic(x^3 - x^2 + 64*y, [y^2+y+1,2], 5) + %3 = [Mod((2^3 + O(2^5))*y + (2^3 + O(2^5)), y^2 + y + 1), + Mod((2^3 + 2^4 + O(2^5))*y + (2^3 + 2^4 + O(2^5)), y^2 + y + 1), + Mod(1 + O(2^5), y^2 + y + 1)]~ + @eprog + + If \var{pol} has inexact \typ{PADIC} coefficients, this need not + well-defined; in this case, the polynomial is first made integral by + dividing out the $p$-adic content, then lifted to $\Z$ using \tet{truncate} + coefficientwise. Hence the roots given are approximations of the roots of an + exact polynomial which is $p$-adically close to the input. To avoid pitfalls, + we advise to only factor polynomials with exact rational coefficients. + +Function: polrootsreal +Class: basic +Section: polynomials +C-Name: realroots +Prototype: GDGp +Help: polrootsreal(T,{ab}): real roots of the polynomial T with real + coefficients, using Uspensky's method. In interval ab = [a,b] if present. +Description: + (gen,?gen):vec:prec realroots($1, $2, $prec) +Doc: real roots of the polynomial $T$ with real coefficients, multiple + roots being included according to their multiplicity. If the polynomial + does not have rational coefficients, it is first rescaled and rounded. + The roots are given to a relative accuracy of \kbd{realprecision}. + If argument \var{ab} is + present, it must be a vector $[a,b]$ with two components (of type + \typ{INT}, \typ{FRAC} or \typ{INFINITY}) and we restrict to roots belonging + to that closed interval. + \bprog + ? \p9 + ? polrootsreal(x^2-2) + %1 = [-1.41421356, 1.41421356]~ + ? polrootsreal(x^2-2, [1,+oo]) + %2 = [1.41421356]~ + ? polrootsreal(x^2-2, [2,3]) + %3 = []~ + ? polrootsreal((x-1)*(x-2), [2,3]) + %4 = [2.00000000]~ + @eprog\noindent + The algorithm used is a modification of Uspensky's method (relying on + Descartes's rule of sign), following Rouillier and Zimmerman's article + ``Efficient isolation of a polynomial real roots'' + (\url{https://hal.inria.fr/inria-00072518/}). Barring bugs, it is guaranteed + to converge and to give the roots to the required accuracy. + + \misctitle{Remark} If the polynomial $T$ is of the + form $Q(x^{h})$ for some $h\geq 2$ and \var{ab} is omitted, the routine will + apply the algorithm to $Q$ (restricting to nonnegative roots when $h$ is + even), then take $h$-th roots. On the other hand, if you want to specify + \var{ab}, you should apply the routine to $Q$ yourself and a suitable + interval $[a',b']$ using approximate $h$-th roots adapted to your problem: + the function will not perform this change of variables if \var{ab} is present. + +Function: polsturm +Class: basic +Section: polynomials +C-Name: sturmpart +Prototype: lGDGDG +Help: polsturm(T,{ab}): number of distinct real roots of the polynomial + T (in the interval ab = [a,b] if present). +Doc: number of distinct real roots of the real polynomial \var{T}. If + the argument \var{ab} is present, it must be a vector $[a,b]$ with + two real components (of type \typ{INT}, \typ{REAL}, \typ{FRAC} + or \typ{INFINITY}) and we count roots belonging to that closed interval. + + If possible, you should stick to exact inputs, that is avoid \typ{REAL}s in + $T$ and the bounds $a,b$: the result is then guaranteed and we use a fast + algorithm (Uspensky's method, relying on Descartes's rule of sign, see + \tet{polrootsreal}). Otherwise, the polynomial is rescaled and rounded first + and the result may be wrong due to that initial error. If only $a$ or $b$ is + inexact, on the other hand, the interval is first thickened using rational + endpoints and the result remains guaranteed unless there exist a root + \emph{very} close to a nonrational endpoint (which may be missed or unduly + included). + \bprog + ? T = (x-1)*(x-2)*(x-3); + ? polsturm(T) + %2 = 3 + ? polsturm(T, [-oo,2]) + %3 = 2 + ? polsturm(T, [1/2,+oo]) + %4 = 3 + ? polsturm(T, [1, Pi]) \\ Pi inexact: not recommended ! + %5 = 3 + ? polsturm(T*1., [0, 4]) \\ T*1. inexact: not recommended ! + %6 = 3 + ? polsturm(T^2, [0, 4]) \\ not squarefree: roots are not repeated! + %7 = 3 + @eprog + %\syn{NO} + + The library syntax is \fun{long}{RgX_sturmpart}{GEN T, GEN ab} or + \fun{long}{sturm}{GEN T} (for the case \kbd{ab = NULL}). The function + \fun{long}{sturmpart}{GEN T, GEN a, GEN b} is obsolete and deprecated. + +Function: polsubcyclo +Class: basic +Section: polynomials +C-Name: polsubcyclo +Prototype: LLDn +Help: polsubcyclo(n,d,{v='x}): finds an equation (in variable v) for the d-th + degree subfields of Q(zeta_n). Output is a polynomial, or a vector of + polynomials if there are several such fields or none. +Doc: gives polynomials (in variable $v$) defining the (Abelian) subextensions + of degree $d$ of the cyclotomic field $\Q(\zeta_{n})$, where $d\mid \phi(n)$. + + If there is exactly one such extension the output is a polynomial, else it is + a vector of polynomials, possibly empty. To get a vector in all cases, + use \kbd{concat([], polsubcyclo(n,d))}. + + Each such polynomial is the minimal polynomial for a Gaussian period + $\text{Tr}_{\Q(\zeta_{f})/L} (\zeta_{f})$, where $L$ is the degree $d$ + subextension of $\Q(\zeta_{n})$ and $f | n$ is its conductor. In + Galois-theoretic terms, $L = \Q(\zeta_{n})^{H}$, where $H$ runs through all + index $d$ subgroups of $(\Z/n\Z)^{*}$. + + The function \tet{galoissubcyclo} allows to specify exactly which + sub-Abelian extension should be computed by giving $H$. + + \misctitle{Complexity} Ignoring logarithmic factors, \kbd{polsubcyclo} runs + in time $O(n)$. The function \kbd{polsubcyclofast} returns different, less + canonical, polynomials but runs in time $O(d^{4})$, again ignoring logarithmic + factors; thus it can handle much larger values of $n$. + +Function: polsubcyclofast +Class: basic +Section: polynomials +C-Name: polsubcyclofast +Prototype: GLD0,L,D0,L, +Help: polsubcyclofast(n,d,{s=0},{exact=0}): If 1 <= d <= 6 + or a prime, finds an equation for the subfields of Q(zeta_n) with galois + group C_d. Contrary to polsubcyclo, the output is + always a (possibly empty) vector of polynomials. If s = 0 (default) all + signatures, otherwise s = 1 (resp., -1) for totally real (resp., totally + complex). Set exact = 1 for subfields of exact conductor n. +Doc: If $1 \leq d\leq 6$ or a prime, finds an equation for the subfields of + $\Q(\zeta_{n})$ with Galois group $C_{d}$; the special value $d = -4$ provides + the subfields with group $V_{4}=C_{2}\times C_{2}$. Contrary to + \kbd{polsubcyclo}, the + output is always a (possibly empty) vector of polynomials. If $s = 0$ (default) + all signatures, otherwise $s = 1$ (resp., $-1$) for totally real + (resp., totally complex). Set \kbd{exact = 1} for subfields of conductor $n$. + + The argument $n$ can be given as in arithmetic functions: as an integer, as a + factorization matrix, or (preferred) as a pair $[N, \kbd{factor}(N)]$. + + \misctitle{Comparison with \kbd{polsubcyclo}} First \kbd{polsubcyclofast} + does not usually return Gaussian periods, but ad hoc polynomials which do + generate the same field. Roughly speaking (ignoring + logarithmic factors), the complexity of \kbd{polsubcyclo} is independent of + $d$ and the complexity of \kbd{polsubcyclofast} is independent of $n$. + Ignoring logarithmic factors, \kbd{polsubcylo} runs in time $O(n)$ and + \kbd{polsubcyclofast} in time $O(d^{4})$. + So the latter is \emph{much} faster than \kbd{polsubcyclo} if $n$ is large, + but gets slower as $d$ increases and becomes unusable for $d \geq 40$ or so. + + \bprog + ? polsubcyclo(10^7+19,7); + time = 1,852 ms. + ? polsubcyclofast(10^7+19,7); + time = 15 ms. + + ? polsubcyclo(10^17+21,5); \\ won't finish + *** polsubcyclo: user interrupt after 2h + ? polsubcyclofast(10^17+21,5); + time = 3 ms. + + ? polsubcyclofast(10^17+3,7); + time = 26 ms. + + ? polsubcyclo(10^6+117,13); + time = 193 ms. + ? polsubcyclofast(10^6+117,13); + time = 50 ms. + + ? polsubcyclofast(10^6+199,19); + time = 202 ms. + ? polsubcyclo(10^6+199,19); \\ about as fast + time = 3191ms. + + ? polsubcyclo(10^7+271,19); + time = 2,067 ms. + ? polsubcyclofast(10^7+271,19); + time = 201 ms. + @eprog + +Function: polsylvestermatrix +Class: basic +Section: polynomials +C-Name: sylvestermatrix +Prototype: GG +Help: polsylvestermatrix(x,y): forms the sylvester matrix attached to the + two polynomials x and y. Warning: the polynomial coefficients are in + columns, not in rows. +Doc: forms the Sylvester matrix + corresponding to the two polynomials $x$ and $y$, where the coefficients of + the polynomials are put in the columns of the matrix (which is the natural + direction for solving equations afterwards). The use of this matrix can be + essential when dealing with polynomials with inexact entries, since + polynomial Euclidean division doesn't make much sense in this case. + +Function: polsym +Class: basic +Section: polynomials +C-Name: polsym +Prototype: GL +Help: polsym(x,n): column vector of symmetric powers of the roots of x up to n. +Doc: creates the column vector of the \idx{symmetric powers} of the roots of the + polynomial $x$ up to power $n$, using Newton's formula. + +Function: poltchebi +Class: basic +Section: polynomials +C-Name: polchebyshev1 +Prototype: LDn +Obsolete: 2013-04-03 +Help: poltchebi(n,{v='x}): deprecated alias for polchebyshev. +Doc: deprecated alias for \kbd{polchebyshev} + +Function: polteichmuller +Class: basic +Section: polynomials +C-Name: polteichmuller +Prototype: GUL +Help: polteichmuller(T,p,r): return the polynomial whose roots (resp. leading + coef) are the Teichmuller lift of the roots (resp. leading coef) of T, to + p-adic precision r. +Doc: given $T \in \F_{p}[X]$ return the polynomial $P\in \Z_{p}[X]$ whose roots + (resp.~leading coefficient) are the Teichmuller lifts of the roots + (resp.~leading coefficient) of $T$, to $p$-adic precision $r$. If $T$ is + monic, $P$ is the reduction modulo $p^{r}$ of the unique monic polynomial + congruent to $T$ modulo $p$ such that $P(X^{p}) = 0 \pmod{P(X),p^{r}}$. + \bprog + ? T = ffinit(3, 3, 't) + %1 = Mod(1,3)*t^3 + Mod(1,3)*t^2 + Mod(1,3)*t + Mod(2,3) + ? P = polteichmuller(T,3,5) + %2 = t^3 + 166*t^2 + 52*t + 242 + ? subst(P, t, t^3) % (P*Mod(1,3^5)) + %3 = Mod(0, 243) + ? [algdep(a+O(3^5),2) | a <- Vec(P)] + %4 = [x - 1, 5*x^2 + 1, x^2 + 4*x + 4, x + 1] + @eprog\noindent When $T$ is monic and irreducible mod $p$, this provides + a model $\Q_{p}[X]/(P)$ of the unramified extension $\Q_{p}[X] / (T)$ where + the Frobenius has the simple form $X \mod P \mapsto X^{p} \mod P$. + +Function: poltomonic +Class: basic +Section: polynomials +C-Name: poltomonic +Prototype: GD& +Help: poltomonic(T,{&L}): T in Q[x]; returns U monic in Z[x] such that + U(x) = C T(x/L) for some rational C and L. If &L is given, set it to L. +Doc: let $T \in \Q[x]$ be a nonzero polynomial; returns $U$ monic in $\Z[x]$ + such that $U(x) = C T(x/L)$ for some $C,L\in \Q$. If the pointer argument + \kbd{\&L} is present, set \kbd{L} to $L$. + \bprog + ? poltomonic(9*x^2 - 1/2) + %1 = x^2 - 2 + ? U = poltomonic(9*x^2 - 1/2, &L) + %2 = x^2 - 2 + ? L + %3 = 6 + ? U / subst(9*x^2 - 1/2, x, x/L) + %4 = 4 + @eprog + + This function does not compute discriminants or maximal orders and runs + with complexity almost linear in the input size. If $T$ is already monic with + integer coefficient, \kbd{poltomonic} may still transform it if $\Z[x]/(T)$ + is contained in a trivial subring of the maximal order, generated by $L x$: + \bprog + ? poltomonic(x^2 + 4, &L) + %5 = x^2 + 1 + ? L + %6 = 1/2 + @eprog\noindent If $T$ is irreducible, the functions \kbd{polredabs} + (exponential time) and \kbd{polredbest} (polynomial time) also find a monic + integral generating polynomial for the number field $\Q[x]/(T)$, with + explicit guarantees on its size, but are orders of magnitude slower. + +Function: poltschirnhaus +Class: basic +Section: number_fields +C-Name: tschirnhaus +Prototype: G +Help: poltschirnhaus(x): random Tschirnhausen transformation of the + polynomial x. +Doc: applies a random Tschirnhausen + transformation to the polynomial $x$, which is assumed to be nonconstant + and separable, so as to obtain a new equation for the \'etale algebra + defined by $x$. This is for instance useful when computing resolvents, + hence is used by the \kbd{polgalois} function. + +Function: polylog +Class: basic +Section: transcendental +C-Name: polylog0 +Prototype: LGD0,L,p +Help: polylog(m,x,{flag=0}): m-th polylogarithm of x. flag is optional, and + can be 0: default, 1: D_m~-modified m-th polylog of x, 2: D_m-modified m-th + polylog of x, 3: P_m-modified m-th polylog of x. +Doc: one of the different polylogarithms, depending on $\fl$: + + If $\fl=0$ or is omitted: $m^{\text{th}}$ polylogarithm of $x$, i.e.~analytic + continuation of the power series $\text{Li}_{m}(x)=\sum_{n\ge1}x^{n}/n^{m}$ + ($x < 1$). Uses the functional equation linking the values at $x$ and $1/x$ + to restrict to the case $|x|\leq 1$, then the power series when + $|x|^{2}\le1/2$, and the power series expansion in $\log(x)$ otherwise. + + Using $\fl$, computes a modified $m^{\text{th}}$ polylogarithm of $x$. + We use Zagier's notations; let $\Re_{m}$ denote $\Re$ or $\Im$ depending + on whether $m$ is odd or even: + + If $\fl=1$: compute $\tilde D_{m}(x)$, defined for $|x|\le1$ by + $$\Re_{m}\left(\sum_{k=0}^{m-1} \dfrac{(-\log|x|)^{k}}{k!}\text{Li}_{m-k}(x) + +\dfrac{(-\log|x|)^{m-1}}{m!}\log|1-x|\right).$$ + + If $\fl=2$: compute $D_{m}(x)$, defined for $|x|\le1$ by + $$\Re_{m}\left(\sum_{k=0}^{m-1}\dfrac{(-\log|x|)^{k}}{k!}\text{Li}_{m-k}(x) + -\dfrac{1}{2}\dfrac{(-\log|x|)^{m}}{m!}\right).$$ + + If $\fl=3$: compute $P_{m}(x)$, defined for $|x|\le1$ by + $$\Re_{m}\left(\sum_{k=0}^{m-1}\dfrac{2^{k}B_{k}}{k!} + (\log|x|)^{k}\text{Li}_{m-k}(x) + -\dfrac{2^{m-1}B_{m}}{m!}(\log|x|)^{m}\right).$$ + + These three functions satisfy the functional equation + $f_{m}(1/x) = (-1)^{m-1}f_{m}(x)$. +Variant: Also available is + \fun{GEN}{gpolylog}{long m, GEN x, long prec} ($\fl = 0$). + +Function: polylogmult +Class: basic +Section: transcendental +C-Name: polylogmult_interpolate +Prototype: GDGDGp +Help: polylogmult(s,{z},{t=0}): multiple polylogarithm value at integral + s = [s1,...,sr] with argument z = [z1,...,zr]. If z is omitted, assume + z = [1,...,1], i.e., multiple zeta value. More generally, return Yamamoto's + interpolation at t (ordinary multiple polylog at t = 0 and star value at + t = 1). +Doc: For $s$ a vector of positive integers and $z$ a vector of complex + numbers of the same length, returns the multiple polylogarithm value (MPV) + $$\zeta(s_{1},\dots, s_{r}; z_{1},\dots,z_{r}) + = \sum_{n_{1}>\dots>n_{r}>0} + \prod_{1\le i\le r}z_{i}^{n_{i}}/n_{i}^{s_{i}}.$$ + If $z$ is omitted, assume $z=[1,\dots,1]$, i.e., Multiple Zeta Value. + More generally, return Yamamoto's interpolation between ordinary multiple + polylogarithms ($t = 0$) and star polylogarithms ($t = 1$, using the + condition $n_{1}\ge \dots \ge n_{r} > 0$), evaluated at $t$. + + We must have $|z_{1}\cdots z_{i}|\le1$ for all $i$, and if $s_{1}=1$ we + must have $z_{1}\ne1$. + \bprog + ? 8*polylogmult([2,1],[-1,1]) - zeta(3) + %1 = 0.E-38 + @eprog\noindent + \misctitle{Warning} The algorithm used converges when the $z_{i}$ are + $\pm 1$. It may not converge as some $z_{i} \neq 1$ becomes too close to $1$, + even at roots of $1$ of moderate order: + \bprog + ? polylogmult([2,1], (99+20*I)/101 * [1,1]) + *** polylogmult: sorry, polylogmult in this range is not yet implemented. + ? polylogmult([2,1], exp(I*Pi/20)* [1,1]) + *** polylogmult: sorry, polylogmult in this range is not yet implemented. + @eprog\noindent More precisely, if $y_{i} := 1 / (z_{1}\cdots z_{i})$ and + $$ v := \min_{i < j; y_{i} \neq 1} |(1 - y_{i}) y_{j}| > 1/4$$ + then the algorithm computes the value up to a $2^{-b}$ absolute error + in $O(k^{2}N)$ operations on floating point numbers of $O(N)$ bits, + where $k = \sum_{i} s_{i}$ is the weight and $N = b / \log_{2} (4v)$. +Variant: Also available is + \fun{GEN}{polylogmult}{GEN s, GEN z, long prec} ($t$ is \kbd{NULL}). + +Function: polzagier +Class: basic +Section: polynomials +C-Name: polzag +Prototype: LL +Help: polzagier(n,m): Zagier's polynomials of index n,m. +Doc: creates Zagier's polynomial $P_{n}^{(m)}$ used in + the functions \kbd{sumalt} and \kbd{sumpos} (with $\fl=1$), see + ``Convergence acceleration of alternating series'', Cohen et al., + \emph{Experiment.~Math.}, vol.~9, 2000, pp.~3--12. + + If $m < 0$ or $m \ge n$, $P_{n}^{(m)} = 0$. + We have + $P_{n} := P_{n}^{(0)}$ is $T_{n}(2x-1)$, where $T_{n}$ is the Legendre + polynomial of the second kind. For $n > m > 0$, $P_{n}^{(m)}$ is the $m$-th + difference with step $2$ of the sequence $n^{m+1}P_{n}$; in this case, it + satisfies + $$2 P_{n}^{(m)}(sin^{2} t) + = \dfrac{d^{m+1}}{dt^{m+1}} (\sin(2t)^{m} \sin(2(n-m)t)).$$ + + %@article {MR2001m:11222, + % AUTHOR = {Cohen, Henri and Rodriguez Villegas, Fernando and Zagier, Don}, + % TITLE = {Convergence acceleration of alternating series}, + % JOURNAL = {Experiment. Math.}, + % VOLUME = {9}, + % YEAR = {2000}, + % NUMBER = {1}, + % PAGES = {3--12}, + %} + +Function: powers +Class: basic +Section: linear_algebra +C-Name: gpowers0 +Prototype: GLDG +Help: powers(x,n,{x0}): return the vector [1,x,...,x^n] if x0 is omitted, + and [x0, x0*x, ..., x0*x^n] otherwise. +Description: + (gen, small):vec gpowers($1, $2) +Doc: for nonnegative $n$, return the vector with $n+1$ components + $[1,x,\dots,x^{n}]$ if \kbd{x0} is omitted, and + $[x_{0}, x_{0}*x, ..., x_{0}*x^{n}]$ otherwise. + \bprog + ? powers(Mod(3,17), 4) + %1 = [Mod(1, 17), Mod(3, 17), Mod(9, 17), Mod(10, 17), Mod(13, 17)] + ? powers(Mat([1,2;3,4]), 3) + %2 = [[1, 0; 0, 1], [1, 2; 3, 4], [7, 10; 15, 22], [37, 54; 81, 118]] + ? powers(3, 5, 2) + %3 = [2, 6, 18, 54, 162, 486] + @eprog\noindent When $n < 0$, the function returns the empty vector \kbd{[]}. +Variant: Also available is + \fun{GEN}{gpowers}{GEN x, long n} when \kbd{x0} is \kbd{NULL}. + +Function: precision +Class: basic +Section: conversions +C-Name: precision00 +Prototype: GDG +Help: precision(x,{n}): if n is present, return x at precision n. If n is + omitted, return real precision of object x. +Doc: the function behaves differently according to whether $n$ is + present or not. If $n$ is missing, the function returns + the floating point precision in decimal digits of the PARI object $x$. If $x$ + has no floating point component, the function returns \kbd{+oo}. + \bprog + ? precision(exp(1e-100)) + %1 = 154 \\ 154 significant decimal digits + ? precision(2 + x) + %2 = +oo \\ exact object + ? precision(0.5 + O(x)) + %3 = 38 \\ floating point accuracy, NOT series precision + ? precision( [ exp(1e-100), 0.5 ] ) + %4 = 38 \\ minimal accuracy among components + @eprog\noindent Using \kbd{getlocalprec()} allows to retrieve + the working precision (as modified by possible \kbd{localprec} + statements). + + If $n$ is present, the function creates a new object equal to $x$ with a new + floating point precision $n$: $n$ is the number of desired significant + \emph{decimal} digits. If $n$ is smaller than the precision of a \typ{REAL} + component of $x$, it is truncated, otherwise it is extended with zeros. + For non-floating-point types, no change. +Variant: Also available are \fun{GEN}{gprec}{GEN x, long n} and + \fun{long}{precision}{GEN x}. In both, the accuracy is expressed in + \emph{words} (32-bit or 64-bit depending on the architecture). + +Function: precprime +Class: basic +Section: number_theoretical +C-Name: precprime +Prototype: G +Help: precprime(x): largest pseudoprime <= x, 0 if x<=1. +Description: + (gen):int precprime($1) +Doc: finds the largest pseudoprime (see \tet{ispseudoprime}) less than or equal + to $x$; the input $x$ can be of any real type. + Returns 0 if $x\le1$. Note that if $x$ is a prime, this function returns $x$ + and not the largest prime strictly smaller than $x$. + \bprog + ? precprime(2) + %1 = 2 + ? precprime(Pi) + %2 = 3 + ? precprime(-10) + %3 = 0 \\ primes are positive + @eprog\noindent The function name comes from \emph{prec}eding \emph{prime}. + Despite the name, please note that the function is not guaranteed to return + a prime number (although no counter-example is known at present); the return + value \emph{is} a guaranteed prime if $x \leq 2^{64}$. To rigorously prove + that the result is prime in all cases, use \kbd{isprime}. + +Function: prime +Class: basic +Section: number_theoretical +C-Name: prime +Prototype: L +Help: prime(n): returns the n-th prime (n C-integer). +Doc: the $n^{\text{th}}$ prime number + \bprog + ? prime(10^9) + %1 = 22801763489 + @eprog\noindent Uses checkpointing and a naive $O(n)$ algorithm. Will need + about 30 minutes for $n$ up to $10^{11}$; make sure to start gp with + \kbd{primelimit} at least $\sqrt{p_{n}}$, e.g. the value + $\sqrt{n\log (n\log n)}$ is guaranteed to be sufficient. + +Function: primecert +Class: basic +Section: number_theoretical +C-Name: primecert0 +Prototype: GD0,L,D0,L, +Help: primecert(N,{flag=0},{partial=0}): If N is a prime, return a Primality + Certificate. Return 0 otherwise. If flag = 0 return an ECPP certificate + (Atkin-Morain); if flag = 1 return an N-1 certificate (Pocklington-Lehmer) +Doc: + If N is a prime, return a PARI Primality Certificate for the prime $N$, + as described below. Otherwise, return 0. A Primality Certificate + $c$ can be checked using \tet{primecertisvalid}$(c)$. + + If $\fl = 0$ (default), return an ECPP certificate (Atkin-Morain) + + If $\fl = 0$ and $\var{partial}>0$, return a (potentially) partial + ECPP certificate. + + A PARI ECPP Primality Certificate for the prime $N$ is either a prime + integer $N < 2^{64}$ or a vector \kbd{C} of length $\ell$ whose $i$th + component \kbd{C[i]} is a vector $[N_{i}, t_{i}, s_{i}, a_{i}, P_{i}]$ + of length $5$ + where $N_{1} = N$. It is said to be \emph{valid} if for each + $i = 1, \ldots, \ell$, all of the following conditions are satisfied + + \item $N_{i}$ is a positive integer + + \item $t_{i}$ is an integer such that $t_{i}^{2} < 4N_{i}$ + + \item $s_{i}$ is a positive integer which divides $m_{i}$ where + $m_{i} = N_{i} + 1 - t_{i}$ + + \item If we set $q_{i} = \dfrac{m_{i}}{s_{i}}$, then + + \quad\item $q_{i} > (N_{i}^{1/4}+1)^{2}$ + + \quad\item $q_{i} = N_{i+1}$ if $1 \leq i < l$ + + \quad\item $q_{\ell} \leq 2^{64}$ is prime + + \item $a_{i}$ is an integer + + \quad\item \kbd{P[i]} is a vector of length $2$ representing the affine + point $P_{i} = (x_{i}, y_{i})$ on the elliptic curve + $E: y^{2} = x^{3} + a_{i}x + b_{i}$ modulo $N_{i}$ where + $b_{i} = y_{i}^{2} - x_{i}^{3} - a_{i}x_{i}$ satisfying the following: + + \quad\item $m_{i} P_{i} = \infty$ + + \quad\item $s_{i} P_{i} \neq \infty$ + + Using the following theorem, the data in the vector \kbd{C} allows to + recursively certify the primality of $N$ (and all the $q_{i}$) under the single + assumption that $q_{\ell}$ be prime. + + \misctitle{Theorem} If $N$ is an integer and there exist positive integers + $m, q$ and a point $P$ on the elliptic curve $E: y^{2} = x^{3} + ax + b$ + defined modulo $N$ such that $q > (N^{1/4} + 1)^{2}$, $q$ is a prime divisor + of $m$, $mP = \infty$ and $\dfrac{m}{q}P \neq \infty$, then $N$ is prime. + + A partial certificate is identical except that the condition $q_{\ell} \leq + 2^{64}$ is replaced by $q_{\ell} \leq 2^{partial}$. + Such partial certificate $C$ can be extended to a full certificate by calling + $C=primecert(C)$, or to a longer partial certificate by calling + $C=primecert(C,,b)$ with $b 2^{64}$ satisfying the following + properties: + + \item $p_{i}$ is a prime divisor of $N - 1$; + + \item $a_{i}$ is an integer such that $a_{i}^{N-1} \equiv 1 \pmod{N}$ and + $a_{i}^{(N-1)/p_{i}} - 1$ is coprime with $N$; + + \item $C_{i}$ is an $N-1$ Primality Certificate for $p_{i}$ + + \item The product $F$ of the $p_{i}^{v_{p_{i}}(N-1)}$ is strictly larger than + $N^{1/3}$. Provided that all $p_{i}$ are indeed primes, this implies that any + divisor of $N$ is congruent to $1$ modulo $F$. + + \item The Brillhart--Lehmer--Selfridge criterion is satisfied: when we write + $N = 1 + c_{1} F + c_{2} F^{2}$ in base $F$ the polynomial + $1 + c_{1} X + c_{2} X^{2}$ + is irreducible over $\Z$, i.e. $c_{1}^{2} - 4c_{2}$ is not a square. This + implies that $N$ is prime. + + This algorithm requires factoring partially $p-1$ for various prime integers + $p$ with an unfactored parted $\leq p^{2/3}$ and this may be exceedingly + slow compared to the default. + + The algorithm fails if one of the pseudo-prime factors is not prime, which is + exceedingly unlikely and well worth a bug report. Note that if you monitor + the algorithm at a high enough debug level, you may see warnings about + untested integers being declared primes. This is normal: we ask for partial + factorizations (sufficient to prove primality if the unfactored part is not + too large), and \kbd{factor} warns us that the cofactor hasn't been tested. + It may or may not be tested later, and may or may not be prime. This does + not affect the validity of the whole Primality Certificate. +Variant: Also available is + \fun{GEN}{ecpp0}{GEN N, long partial} ($\fl = 0$). + +Function: primecertexport +Class: basic +Section: number_theoretical +C-Name: primecertexport +Prototype: GD0,L, +Help: primecertexport(cert,{format=0}): Returns a string suitable for + print/write to display a primality certificate. +Doc: + Returns a string suitable for print/write to display a primality certificate + from \tet{primecert}, the format of which depends on the value of \kbd{format}: + + \item 0 (default): Human-readable format. See \kbd{??primecert} for the + meaning of the successive $N, t, s, a, m, q, E, P$. The integer $D$ is the + negative fundamental discriminant \kbd{coredisc}$(t^{2} - 4N)$. + + \item 1: Primo format 4. + + \item 2: MAGMA format. + + Currently, only ECPP Primality Certificates are supported. + + \bprog + ? cert = primecert(10^35+69); + ? s = primecertexport(cert); \\ Human-readable + ? print(s) + [1] + N = 100000000000000000000000000000000069 + t = 546867911035452074 + s = 2963504668391148 + a = 0 + D = -3 + m = 99999999999999999453132088964547996 + q = 33743830764501150277 + E = [0, 1] + P = [21567861682493263464353543707814204, + 49167839501923147849639425291163552] + [2] + N = 33743830764501150277 + t = -11610830419 + s = 734208843 + a = 0 + D = -3 + m = 33743830776111980697 + q = 45959444779 + E = [0, 25895956964997806805] + P = [29257172487394218479, 3678591960085668324] + + \\ Primo format + ? s = primecertexport(cert,1); write("cert.out", s); + + \\ Magma format, write to file + ? s = primecertexport(cert,2); write("cert.m", s); + + ? cert = primecert(10^35+69, 1); \\ N-1 certificate + ? primecertexport(cert) + *** at top-level: primecertexport(cert) + *** ^--------------------- + *** primecertexport: sorry, N-1 certificate is not yet implemented. + @eprog + +Function: primecertisvalid +Class: basic +Section: number_theoretical +C-Name: primecertisvalid +Prototype: lG +Help: primecertisvalid(cert): Verifies if cert is a valid PARI ECPP Primality certificate. +Doc: + Verifies if cert is a valid PARI ECPP Primality certificate, as described + in \kbd{??primecert}. + \bprog + ? cert = primecert(10^35 + 69) + %1 = [[100000000000000000000000000000000069, 5468679110354 + 52074, 2963504668391148, 0, [60737979324046450274283740674 + 208692, 24368673584839493121227731392450025]], [3374383076 + 4501150277, -11610830419, 734208843, 0, [26740412374402652 + 72 4, 6367191119818901665]], [45959444779, 299597, 2331, 0 + , [18022351516, 9326882 51]]] + ? primecertisvalid(cert) + %2 = 1 + + ? cert[1][1]++; \\ random perturbation + ? primecertisvalid(cert) + %4 = 0 \\ no longer valid + ? primecertisvalid(primecert(6)) + %5 = 0 + @eprog + +Function: primepi +Class: basic +Section: number_theoretical +C-Name: primepi +Prototype: G +Help: primepi(x): the prime counting function pi(x) = #{p <= x, p prime}. +Description: + (gen):int primepi($1) +Doc: the prime counting function. Returns the number of + primes $p$, $p \leq x$. + \bprog + ? primepi(10) + %1 = 4; + ? primes(5) + %2 = [2, 3, 5, 7, 11] + ? primepi(10^11) + %3 = 4118054813 + @eprog\noindent Uses checkpointing and a naive $O(x)$ algorithm; + make sure to start gp with \kbd{primelimit} at least $\sqrt{x}$. + +Function: primes +Class: basic +Section: number_theoretical +C-Name: primes0 +Prototype: G +Help: primes(n): returns the vector of the first n primes (integer), or the + primes in interval n = [a,b]. +Doc: creates a row vector whose components are the first $n$ prime numbers. + (Returns the empty vector for $n \leq 0$.) A \typ{VEC} $n = [a,b]$ is also + allowed, in which case the primes in $[a,b]$ are returned + \bprog + ? primes(10) \\ the first 10 primes + %1 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + ? primes([0,29]) \\ the primes up to 29 + %2 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + ? primes([15,30]) + %3 = [17, 19, 23, 29] + @eprog + +Function: print +Class: basic +Section: programming/specific +C-Name: print +Prototype: vs* +Help: print({str}*): outputs its string arguments (in raw format) ending with + a newline. +Description: + (?gen,...):void pari_printf("${2 format_string}\n"${2 format_args}) +Doc: outputs its arguments in raw format ending with a newline. + The arguments are converted to strings following the rules in + \secref{se:strings}. + \bprog + ? m = matid(2); + ? print(m) \\ raw format + [1, 0; 0, 1] + ? printp(m) \\ prettymatrix format + + [1 0] + + [0 1] + @eprog + +Function: print1 +Class: basic +Section: programming/specific +C-Name: print1 +Prototype: vs* +Help: print1({str}*): outputs its string arguments (in raw format) without + ending with newline. +Description: + (?gen,...):void pari_printf("${2 format_string}"${2 format_args}) +Doc: outputs its arguments in raw + format, without ending with a newline. Note that you can still embed newlines + within your strings, using the \b{n} notation~! + The arguments are converted to strings following the rules in + \secref{se:strings}. + +Function: printf +Class: basic +Section: programming/specific +C-Name: printf0 +Prototype: vss* +Help: printf(fmt,{x}*): prints its arguments according to the format fmt. +Doc: This function is based on the C library command of the same name. + It prints its arguments according to the format \var{fmt}, which specifies how + subsequent arguments are converted for output. The format is a + character string composed of zero or more directives: + + \item ordinary characters (not \kbd{\%}), printed unchanged, + + \item conversions specifications (\kbd{\%} followed by some characters) + which fetch one argument from the list and prints it according to the + specification. + + More precisely, a conversion specification consists in a \kbd{\%}, one or more + optional flags (among \kbd{\#}, \kbd{0}, \kbd{-}, \kbd{+}, ` '), an optional + decimal digit string specifying a minimal field width, an optional precision + in the form of a period (`\kbd{.}') followed by a decimal digit string, and + the conversion specifier (among \kbd{d},\kbd{i}, \kbd{o}, \kbd{u}, + \kbd{x},\kbd{X}, \kbd{p}, \kbd{e},\kbd{E}, \kbd{f}, \kbd{g},\kbd{G}, \kbd{s}). + + \misctitle{The flag characters} The character \kbd{\%} is followed by zero or + more of the following flags: + + \item \kbd{\#}: the value is converted to an ``alternate form''. For + \kbd{o} conversion (octal), a \kbd{0} is prefixed to the string. For \kbd{x} + and \kbd{X} conversions (hexa), respectively \kbd{0x} and \kbd{0X} are + prepended. For other conversions, the flag is ignored. + + \item \kbd{0}: the value should be zero padded. For + \kbd{d}, + \kbd{i}, + \kbd{o}, + \kbd{u}, + \kbd{x}, + \kbd{X} + \kbd{e}, + \kbd{E}, + \kbd{f}, + \kbd{F}, + \kbd{g}, and + \kbd{G} conversions, the value is padded on the left with zeros rather than + blanks. (If the \kbd{0} and \kbd{-} flags both appear, the \kbd{0} flag is + ignored.) + + \item \kbd{-}: the value is left adjusted on the field boundary. (The + default is right justification.) The value is padded on the right with + blanks, rather than on the left with blanks or zeros. A \kbd{-} overrides a + \kbd{0} if both are given. + + \item \kbd{` '} (a space): a blank is left before a positive number + produced by a signed conversion. + + \item \kbd{+}: a sign (+ or -) is placed before a number produced by a + signed conversion. A \kbd{+} overrides a space if both are used. + + \misctitle{The field width} An optional decimal digit string (whose first + digit is nonzero) specifying a \emph{minimum} field width. If the value has + fewer characters than the field width, it is padded with spaces on the left + (or right, if the left-adjustment flag has been given). In no case does a + small field width cause truncation of a field; if the value is wider than + the field width, the field is expanded to contain the conversion result. + Instead of a decimal digit string, one may write \kbd{*} to specify that the + field width is given in the next argument. + + \misctitle{The precision} An optional precision in the form of a period + (`\kbd{.}') followed by a decimal digit string. This gives + the number of digits to appear after the radix character for \kbd{e}, + \kbd{E}, \kbd{f}, and \kbd{F} conversions, the maximum number of significant + digits for \kbd{g} and \kbd{G} conversions, and the maximum number of + characters to be printed from an \kbd{s} conversion. + Instead of a decimal digit string, one may write \kbd{*} to specify that the + field width is given in the next argument. + + \misctitle{The length modifier} This is ignored under \kbd{gp}, but + necessary for \kbd{libpari} programming. Description given here for + completeness: + + \item \kbd{l}: argument is a \kbd{long} integer. + + \item \kbd{P}: argument is a \kbd{GEN}. + + \misctitle{The conversion specifier} A character that specifies the type of + conversion to be applied. + + \item \kbd{d}, \kbd{i}: a signed integer. + + \item \kbd{o}, \kbd{u}, \kbd{x}, \kbd{X}: an unsigned integer, converted + to unsigned octal (\kbd{o}), decimal (\kbd{u}) or hexadecimal (\kbd{x} or + \kbd{X}) notation. The letters \kbd{abcdef} are used for \kbd{x} + conversions; the letters \kbd{ABCDEF} are used for \kbd{X} conversions. + + \item \kbd{e}, \kbd{E}: the (real) argument is converted in the style + \kbd{[ -]d.ddd e[ -]dd}, where there is one digit before the decimal point, + and the number of digits after it is equal to the precision; if the + precision is missing, use the current \kbd{realprecision} for the total + number of printed digits. If the precision is explicitly 0, no decimal-point + character appears. An \kbd{E} conversion uses the letter \kbd{E} rather + than \kbd{e} to introduce the exponent. + + \item \kbd{f}, \kbd{F}: the (real) argument is converted in the style + \kbd{[ -]ddd.ddd}, where the number of digits after the decimal point + is equal to the precision; if the precision is missing, use the current + \kbd{realprecision} for the total number of printed digits. If the precision + is explicitly 0, no decimal-point character appears. If a decimal point + appears, at least one digit appears before it. + + \item \kbd{g}, \kbd{G}: the (real) argument is converted in style + \kbd{e} or \kbd{f} (or \kbd{E} or \kbd{F} for \kbd{G} conversions) + \kbd{[ -]ddd.ddd}, where the total number of digits printed + is equal to the precision; if the precision is missing, use the current + \kbd{realprecision}. If the precision is explicitly 0, it is treated as 1. + Style \kbd{e} is used when + the decimal exponent is $< -4$, to print \kbd{0.}, or when the integer + part cannot be decided given the known significant digits, and the \kbd{f} + format otherwise. + + \item \kbd{c}: the integer argument is converted to an unsigned char, and the + resulting character is written. + + \item \kbd{s}: convert to a character string. If a precision is given, no + more than the specified number of characters are written. + + \item \kbd{p}: print the address of the argument in hexadecimal (as if by + \kbd{\%\#x}). + + \item \kbd{\%}: a \kbd{\%} is written. No argument is converted. The complete + conversion specification is \kbd{\%\%}. + + \noindent Examples: + + \bprog + ? printf("floor: %d, field width 3: %3d, with sign: %+3d\n", Pi, 1, 2); + floor: 3, field width 3: 1, with sign: +2 + + ? printf("%.5g %.5g %.5g\n",123,123/456,123456789); + 123.00 0.26974 1.2346 e8 + + ? printf("%-2.5s:%2.5s:%2.5s\n", "P", "PARI", "PARIGP"); + P :PARI:PARIG + + \\ min field width and precision given by arguments + ? x = 23; y=-1/x; printf("x=%+06.2f y=%+0*.*f\n", x, 6, 2, y); + x=+23.00 y=-00.04 + + \\ minimum fields width 5, pad left with zeroes + ? for (i = 2, 5, printf("%05d\n", 10^i)) + 00100 + 01000 + 10000 + 100000 \\@com don't truncate fields whose length is larger than the minimum width + ? printf("%.2f |%06.2f|", Pi,Pi) + 3.14 | 3.14| + @eprog\noindent All numerical conversions apply recursively to the entries + of complex numbers, vectors and matrices: + \bprog + ? printf("%4d", [1,2,3]); + [ 1, 2, 3] + ? printf("%5.2f", mathilbert(3)); + [ 1.00 0.50 0.33] + + [ 0.50 0.33 0.25] + + [ 0.33 0.25 0.20] + ? printf("%.3g", Pi+I) + 3.14+1.00I + @eprog + \misctitle{Technical note} Our implementation of \tet{printf} + deviates from the C89 and C99 standards in a few places: + + \item whenever a precision is missing, the current \kbd{realprecision} is + used to determine the number of printed digits (C89: use 6 decimals after + the radix character). + + \item in conversion style \kbd{e}, we do not impose that the + exponent has at least two digits; we never write a \kbd{+} sign in the + exponent; 0 is printed in a special way, always as \kbd{0.E\var{exp}}. + + \item in conversion style \kbd{f}, we switch to style \kbd{e} if the + exponent is greater or equal to the precision. + + \item in conversion \kbd{g} and \kbd{G}, we do not remove trailing zeros + from the fractional part of the result; nor a trailing decimal point; + 0 is printed in a special way, always as \kbd{0.E\var{exp}}. +Variant: + The variadic version \fun{void}{pari_printf}{const char *fmt, ...} is usually preferable. + +Function: printp +Class: basic +Section: programming/specific +C-Name: printp +Prototype: vs* +Help: printp({str}*): outputs its string arguments (in prettymatrix format) + ending with a newline. +Description: + (?gen,...):void pari_printf("${2 format_string}\n"${2 format_args}) +Doc: outputs its arguments in prettymatrix format, ending with a + newline. The arguments are converted to strings following the rules in + \secref{se:strings}. + \bprog + ? m = matid(2); + ? print(m) \\ raw format + [1, 0; 0, 1] + ? printp(m) \\ prettymatrix format + + [1 0] + + [0 1] + @eprog + +Function: printsep +Class: basic +Section: programming/specific +C-Name: printsep +Prototype: vss* +Help: printsep(sep,{str}*): outputs its string arguments (in raw format), + separated by 'sep', ending with a newline. +Doc: outputs its arguments in raw format, ending with a newline. + The arguments are converted to strings following the rules in + \secref{se:strings}. Successive entries are separated by \var{sep}: + \bprog + ? printsep(":", 1,2,3,4) + 1:2:3:4 + @eprog + +Function: printsep1 +Class: basic +Section: programming/specific +C-Name: printsep1 +Prototype: vss* +Help: printsep1(sep,{str}*): outputs its string arguments (in raw format), + separated by 'sep', without ending with a newline. +Doc: outputs its arguments in raw format, without ending with a + newline. The arguments are converted to strings following the rules in + \secref{se:strings}. Successive entries are separated by \var{sep}: + \bprog + ? printsep1(":", 1,2,3,4);print("|") + 1:2:3:4| + @eprog + +Function: printtex +Class: basic +Section: programming/specific +C-Name: printtex +Prototype: vs* +Help: printtex({str}*): outputs its string arguments in TeX format. +Doc: outputs its arguments in \TeX\ format. This output can then be + used in a \TeX\ manuscript, see \kbd{strtex} for details. The arguments are + converted to strings following the rules in \secref{se:strings}. The printing + is done on the standard output. If you want to print it to a file you should + use \kbd{writetex} (see there). + + Another possibility is to enable the \tet{log} default + (see~\secref{se:defaults}). + You could for instance do:\sidx{logfile} + % + \bprog + default(logfile, "new.tex"); + default(log, 1); + printtex(result); + @eprog + +Function: prod +Class: basic +Section: sums +C-Name: produit +Prototype: V=GGEDG +Help: prod(X=a,b,expr,{x=1}): x times the product (X runs from a to b) of + expression. +Doc: product of expression + \var{expr}, initialized at $x$, the formal parameter $X$ going from $a$ to + $b$. As for \kbd{sum}, the main purpose of the initialization parameter $x$ + is to force the type of the operations being performed. For example if it is + set equal to the integer 1, operations will start being done exactly. If it + is set equal to the real $1.$, they will be done using real numbers having + the default precision. If it is set equal to the power series $1+O(X^{k})$ for + a certain $k$, they will be done using power series of precision at most $k$. + These are the three most common initializations. + + \noindent As an extreme example, compare + + \bprog + ? prod(i=1, 100, 1 - X^i); \\@com this has degree $5050$ !! + time = 128 ms. + ? prod(i=1, 100, 1 - X^i, 1 + O(X^101)) + time = 8 ms. + %2 = 1 - X - X^2 + X^5 + X^7 - X^12 - X^15 + X^22 + X^26 - X^35 - X^40 + \ + X^51 + X^57 - X^70 - X^77 + X^92 + X^100 + O(X^101) + @eprog\noindent + Of course, in this specific case, it is faster to use \tet{eta}, + which is computed using Euler's formula. + \bprog + ? prod(i=1, 1000, 1 - X^i, 1 + O(X^1001)); + time = 589 ms. + ? \ps1000 + seriesprecision = 1000 significant terms + ? eta(X) - % + time = 8ms. + %4 = O(X^1001) + @eprog + + \synt{produit}{GEN a, GEN b, char *expr, GEN x}. + +Function: prodeuler +Class: basic +Section: sums +C-Name: prodeuler0 +Prototype: V=GGEp +Help: prodeuler(p=a,b,expr): Euler product (p runs over the primes between a + and b) of real or complex expression, as a floating point approximation. +Doc: product of expression \var{expr}, initialized at \kbd{1.0} + (i.e.~to a floating point number equal to 1 to the + current \kbd{realprecision}), the formal parameter $p$ ranging over the prime + numbers between $a$ and $b$.\sidx{Euler product} + \bprog + ? prodeuler(p = 2, 10^4, 1 - p^-2) + %1 = 0.60793306911405513018380499671124428015 + ? P = 1; forprime(p = 2, 10^4, P *= (1 - p^-2)) + ? exponent(numerator(P)) + %3 = 22953 + @eprog\noindent The function returns a floating point number because, + as the second expression shows, such products are usually intractably + large rational numbers when computed symbolically. + If the expression is a rational function, \kbd{prodeulerrat} computes the + product over all primes: + \bprog + ? prodeulerrat(1 - p^-2) + %4 = 0.60792710185402662866327677925836583343 + ? 6/Pi^2 + %3 = 0.60792710185402662866327677925836583343 + @eprog + + \synt{prodeuler}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b, long prec}. + +Function: prodeulerrat +Class: basic +Section: sums +C-Name: prodeulerrat +Prototype: GDGD2,L,p +Help: prodeulerrat(F,{s=1},{a=2}): product from primes p = a to infinity of + F(p^s), where F is a rational function. +Doc: $\prod_{p\ge a}F(p^{s})$, where the product is taken over prime numbers + and $F$ is a rational function. + \bprog + ? prodeulerrat(1+1/q^3,1) + %1 = 1.1815649490102569125693997341604542605 + ? zeta(3)/zeta(6) + %2 = 1.1815649490102569125693997341604542606 + @eprog + +Function: prodinf +Class: basic +Section: sums +C-Name: prodinf0 +Prototype: V=GED0,L,p +Help: prodinf(X=a,expr,{flag=0}): infinite product (X goes from a to + infinity) of real or complex expression. flag can be 0 (default) or 1, in + which case compute the product of the 1+expr instead. +Wrapper: (,G) +Description: + (gen,gen,?0):gen:prec prodinf(${2 cookie}, ${2 wrapper}, $1, $prec) + (gen,gen,1):gen:prec prodinf(${2 cookie}, ${2 wrapper}, $1, $prec) +Doc: \idx{infinite product} of + expression \var{expr}, the formal parameter $X$ starting at $a$. The evaluation + stops when the relative error of the expression minus 1 is less than the + default precision. In particular, divergent products result in infinite + loops. The expressions must always evaluate to an element of $\C$. + + If $\fl=1$, do the product of the ($1+\var{expr}$) instead. + + \synt{prodinf}{void *E, GEN (*eval)(void*,GEN), GEN a, long prec} + ($\fl=0$), or \tet{prodinf1} with the same arguments ($\fl=1$). + +Function: prodnumrat +Class: basic +Section: sums +C-Name: prodnumrat +Prototype: GLp +Help: prodnumrat(F,a): product from n = a to infinity of F(n), where F-1 + is a rational function of degree less than or equal to -2. +Doc: $\prod_{n\ge a}F(n)$, where $F-1$ is a rational function of degree less + than or equal to $-2$. + \bprog + ? prodnumrat(1+1/x^2,1) + %1 = 3.6760779103749777206956974920282606665 + @eprog + +Function: psdraw +Class: basic +Section: graphic +C-Name: psdraw +Prototype: vGD0,L, +Obsolete: 2018-02-01 +Help: psdraw(list,{flag=0}): obsolete function. +Doc: This function is obsolete, use plotexport and write the result to file. + +Function: psi +Class: basic +Section: transcendental +C-Name: gpsi_der +Prototype: GD0,L,p +Help: psi(x,{der}): psi-function at x (der-th derivative of psi if der is set) +Doc: the $\psi$-function of $x$, i.e.~the logarithmic derivative + $\Gamma'(x)/\Gamma(x)$. If $\var{der}$ is set, return the $\var{der}$-th derivative. + For $s$ a \typ{PADIC}, evaluates the $\var{der}$-th derivative of the Morita + $\psi$ function at $s$. +Variant: For a \typ{PADIC} $x$, the function + \fun{GEN}{Qp_psi}{GEN x, long der} is also available. + For $\var{der} = 0$, + \fun{GEN}{gpsi}{GEN x, long prec} is also available. + +Function: psploth +Class: basic +Section: graphic +C-Name: psploth0 +Prototype: V=GGED0,M,D0,L,p\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 +Obsolete: 2018-02-01 +Help: psploth(X=a,b,expr,{flags=0},{n=0}): obsolete function. +Wrapper: (,,G) +Description: + (gen,gen,gen,?small,?small):gen:prec psploth(${3 cookie}, ${3 wrapper}, $1, $2, $4, $5, $prec) +Doc: This function is obsolete, use plothexport and write the result to file. + +Function: psplothraw +Class: basic +Section: graphic +C-Name: psplothraw +Prototype: GGD0,L, +Obsolete: 2018-02-01 +Help: psplothraw(listx,listy,{flag=0}): obsolete function. +Doc: This function is obsolete, use plothrawexport and write the result to file. + +Function: qfauto +Class: basic +Section: linear_algebra +C-Name: qfauto0 +Prototype: GDG +Help: qfauto(G,{fl}): automorphism group of the positive definite quadratic + form G. +Doc: + $G$ being a square and symmetric matrix with integer entries representing a + positive definite quadratic form, outputs the automorphism group of the + associate lattice. + Since this requires computing the minimal vectors, the computations can + become very lengthy as the dimension grows. $G$ can also be given by an + \kbd{qfisominit} structure. + See \kbd{qfisominit} for the meaning of \var{fl}. + + The output is a two-components vector $[o,g]$ where $o$ is the group order + and $g$ is the list of generators (as a vector). For each generator $H$, + the equality $G={^{t}}H\*G\*H$ holds. + + The interface of this function is experimental and will likely change in the + future. + + This function implements an algorithm of Plesken and Souvignier, following + Souvignier's implementation. + \bprog + ? K = matkerint(Mat(concat([vector(23,i,2*i+1), 51, 145]))); + ? M = matdiagonal(vector(25,i,if(i==25,-1,1))); + ? L24 = K~ * M * K; \\ the Leech lattice + ? [o,g] = qfauto(L24); o + %4 = 8315553613086720000 + ? #g + %5 = 2 + @eprog +Variant: The function \fun{GEN}{qfauto}{GEN G, GEN fl} is also available + where $G$ is a vector of \kbd{zm} matrices. + +Function: qfautoexport +Class: basic +Section: linear_algebra +C-Name: qfautoexport +Prototype: GD0,L, +Help: qfautoexport(qfa,{flag}): qfa being an automorphism group as output by + qfauto, output a string representing the underlying matrix group in + GAP notation (default) or Magma notation (flag = 1). +Doc: \var{qfa} being an automorphism group as output by + \tet{qfauto}, export the underlying matrix group as a string suitable + for (no flags or $\fl=0$) GAP or ($\fl=1$) Magma. The following example + computes the size of the matrix group using GAP: + \bprog + ? G = qfauto([2,1;1,2]) + %1 = [12, [[-1, 0; 0, -1], [0, -1; 1, 1], [1, 1; 0, -1]]] + ? s = qfautoexport(G) + %2 = "Group([[-1, 0], [0, -1]], [[0, -1], [1, 1]], [[1, 1], [0, -1]])" + ? extern("echo \"Order("s");\" | gap -q") + %3 = 12 + @eprog + +Function: qfbclassno +Class: basic +Section: number_theoretical +C-Name: qfbclassno0 +Prototype: GD0,L, +Help: qfbclassno(D,{flag=0}): class number of discriminant D using Shanks's + method by default. If (optional) flag is set to 1, use Euler products. +Doc: ordinary class number of the quadratic order of discriminant $D$, for + ``small'' values of $D$. + + \item if $D > 0$ or $\fl = 1$, use a $O(|D|^{1/2})$ + algorithm (compute $L(1,\chi_{D})$ with the approximate functional equation). + This is slower than \tet{quadclassunit} as soon as $|D| \approx 10^{2}$ or + so and is not meant to be used for large $D$. + + \item if $D < 0$ and $\fl = 0$ (or omitted), use a $O(|D|^{1/4})$ + algorithm (Shanks's baby-step/giant-step method). It should + be faster than \tet{quadclassunit} for small values of $D$, say + $|D| < 10^{18}$. + + \misctitle{Important warning} In the latter case, this function only + implements part of \idx{Shanks}'s method (which allows to speed it up + considerably). It gives unconditionnally correct results for + $|D| < 2\cdot 10^{10}$, but may give incorrect results for larger values + if the class + group has many cyclic factors. We thus recommend to double-check results + using the function \kbd{quadclassunit}, which is about 2 to 3 times slower in + the range $|D| \in [10^{10}, 10^{18}]$, assuming GRH. We currently have no + counter-examples but they should exist: we would appreciate a bug report if + you find one. + + \misctitle{Warning} Contrary to what its name implies, this routine does not + compute the number of classes of binary primitive forms of discriminant $D$, + which is equal to the \emph{narrow} class number. The two notions are the same + when $D < 0$ or the fundamental unit $\varepsilon$ has negative norm; when $D + > 0$ and $N\varepsilon > 0$, the number of classes of forms is twice the + ordinary class number. This is a problem which we cannot fix for backward + compatibility reasons. Use the following routine if you are only interested + in the number of classes of forms: + \bprog + ? QFBclassno(D) = qfbclassno(D) * if (D > 0 && quadunitnorm(D) > 0, 2, 1) + ? QFBclassno(136) + %1 = 4 + ? qfbclassno(136) + %2 = 2 + ? quadunitnorm(136) + %3 = 1 + ? bnfnarrow(bnfinit(x^2 - 136)).cyc + %4 = [4] \\ narrow class group is cyclic ~ Z/4Z + @eprog\noindent Note that the use of \kbd{bnfnarrow} above is only valid + because $136$ is a fundamental discriminant: that function is asymptotically + faster (and returns the group structure, not only its order) but only supports + \emph{maximal} orders. + Here are a few more examples: + \bprog + ? qfbclassno(400000028) \\ D > 0: slow + time = 3,140 ms. + %1 = 1 + ? quadclassunit(400000028).no + time = 20 ms. \\@com{ much faster, assume GRH} + %2 = 1 + ? qfbclassno(-400000028) \\ D < 0: fast enough + time = 0 ms. + %3 = 7253 + ? quadclassunit(-400000028).no + time = 0 ms. + %4 = 7253 + @eprog\noindent See also \kbd{qfbhclassno}. + +Function: qfbcomp +Class: basic +Section: number_theoretical +C-Name: qfbcomp +Prototype: GG +Help: qfbcomp(x,y): Gaussian composition with reduction of the binary + quadratic forms x and y. +Doc: \idx{composition} of the binary quadratic forms $x$ and $y$, with + \idx{reduction} of the result. + \bprog + ? x=Qfb(2,3,-10);y=Qfb(5,3,-4); + ? qfbcomp(x,y) + %2 = Qfb(-2, 9, 1) + ? qfbcomp(x,y)==qfbred(qfbcompraw(x,y)) + %3 = 1 + @eprog + +Function: qfbcompraw +Class: basic +Section: number_theoretical +C-Name: qfbcompraw +Prototype: GG +Help: qfbcompraw(x,y): Gaussian composition without reduction of the binary + quadratic forms x and y. +Doc: \idx{composition} of the binary quadratic forms $x$ and $y$, without + \idx{reduction} of the result. This is useful e.g.~to compute a generating + element of an ideal. The result is undefined if $x$ and $y$ do not have the + same discriminant. + \bprog + ? x=Qfb(2,3,-10);y=Qfb(5,3,-4); + ? qfbcompraw(x,y) + %2 = Qfb(10, 3, -2) + ? x=Qfb(2,3,-10);y=Qfb(1,-1,1); + ? qfbcompraw(x,y) + *** at top-level: qfbcompraw(x,y) + *** ^--------------- + *** qfbcompraw: inconsistent qfbcompraw t_QFB , t_QFB. + @eprog + +Function: qfbcornacchia +Class: basic +Section: number_theoretical +C-Name: qfbcornacchia +Prototype: GG +Help: qfbcornacchia(d,n): Solves the equation + x^2+dy^2 = n in integers x and y where d > 0 and + n is prime or 4 times a prime. +Doc: Solves the equation $x^{2} + dy^{2} = n$ in integers $x$ and $y$, where + $d > 0$ and $n$ is prime. Returns the empty vector \kbd{[]} when no solution + exists. It is also allowed to try $n = 4$ times a prime but the answer is + then guaranteed only if $d$ is $3$ mod $4$; more precisely if $d \neq 3$ mod + $4$, the algorithm may fail to find a non-primitive solution. + + This function is a special case of \kbd{qfbsolve} applied to the principal + form in the imaginary quadratic order of discriminant $-4d$ (returning the + solution with non-negative $x$ and $y$). As its name implies, + \kbd{qfbcornacchia} uses Cornacchia's algorithm and runs in time quasi-linear + in $\log n$ (using \kbd{halfgcd}); in practical ranges, \kbd{qfbcornacchia} + should be about twice faster than \kbd{qfbsolve} unless we indicate to the + latter that its second argument is prime (see below). + \bprog + ? qfbcornacchia(1, 113) + %1 = [8, 7] + ? qfbsolve(Qfb(1,0,1), 113) + %2 = [8, 7] + ? qfbcornacchia(1, 4*113) \\ misses the non-primitive solution 2*[8,7] + %3 = [] + ? qfbcornacchia(1, 4*109) \\ finds a non-primitive solution + %4 = [20, 6] + ? p = 122838793181521; isprime(p) + %5 = 1 + ? qfbcornacchia(24, p) + %6 = [10547339, 694995] + ? Q = Qfb(1,0,24); qfbsolve(Q,p) + %7 = [10547339, 694995] + ? for (i=1, 10^5, qfbsolve(Q, p)) + time = 345 ms. + ? for (i=1, 10^5, qfbcornacchia(24,p)) \\ faster + time = 251 ms. + ? for (i=1, 10^5, qfbsolve(Q, Mat([p,1]))) \\ just as fast + time = 251 ms. + @eprog\noindent We used \kbd{Mat([p,1])} to indicate that $p^{1}$ + was the integer factorization of $p$, i.e., that $p$ is prime. Without it, + \kbd{qfbsolve} attempts to factor $p$ and wastes a little time. + +Function: qfbhclassno +Class: basic +Section: number_theoretical +C-Name: hclassno +Prototype: G +Help: qfbhclassno(x): Hurwitz-Kronecker class number of x>0. +Doc: \idx{Hurwitz class number} of $x$, when + $x$ is nonnegative and congruent to 0 or 3 modulo 4, and $0$ for other + values. For $x > 5\cdot 10^{5}$, we assume the GRH, and use \kbd{quadclassunit} + with default parameters. + \bprog + ? qfbhclassno(1) \\ not 0 or 3 mod 4 + %1 = 0 + ? qfbhclassno(3) + %2 = 1/3 + ? qfbhclassno(4) + %3 = 1/2 + ? qfbhclassno(23) + %4 = 3 + @eprog + +Function: qfbil +Class: basic +Section: linear_algebra +C-Name: qfbil +Prototype: GGDG +Obsolete: 2016-08-08 +Help: qfbil(x,y,{q}): this function is obsolete, use qfeval. +Doc: this function is obsolete, use \kbd{qfeval}. + +Function: qfbnucomp +Class: basic +Section: number_theoretical +C-Name: nucomp +Prototype: GGG +Help: qfbnucomp(x,y,L): composite of primitive positive definite quadratic + forms x and y using nucomp and nudupl, where L=[|D/4|^(1/4)] is precomputed. +Doc: \idx{composition} of the primitive positive + definite binary quadratic forms $x$ and $y$ (type \typ{QFB}) using the NUCOMP + and NUDUPL algorithms of \idx{Shanks}, \`a la Atkin. $L$ is any positive + constant, but for optimal speed, one should take $L=|D/4|^{1/4}$, i.e. + \kbd{sqrtnint(abs(D)>>2,4)}, where $D$ is the common discriminant of $x$ and + $y$. When $x$ and $y$ do not have the same discriminant, the result is + undefined. + + The current implementation is slower than the generic routine for small $D$, + and becomes faster when $D$ has about $45$ bits. +Variant: Also available is \fun{GEN}{nudupl}{GEN x, GEN L} when $x=y$. + +Function: qfbnupow +Class: basic +Section: number_theoretical +C-Name: nupow +Prototype: GGDG +Help: qfbnupow(x,n,{L}): n-th power of primitive positive definite quadratic + form x using nucomp and nudupl. +Doc: $n$-th power of the primitive positive definite + binary quadratic form $x$ using \idx{Shanks}'s NUCOMP and NUDUPL algorithms; + if set, $L$ should be equal to \kbd{sqrtnint(abs(D)>>2,4)}, where $D < 0$ is + the discriminant of $x$. + + The current implementation is slower than the generic routine for small + discriminant $D$, and becomes faster for $D \approx 2^{45}$. + +Function: qfbpow +Class: basic +Section: number_theoretical +C-Name: qfbpow +Prototype: GG +Help: qfbpow(x,n): n-th power with reduction of the binary quadratic + form x. +Doc: $n$-th power of the binary quadratic form + $x$, computed with \idx{reduction} (i.e.~using \kbd{qfbcomp}). + +Function: qfbpowraw +Class: basic +Section: number_theoretical +C-Name: qfbpowraw +Prototype: GL +Help: qfbpowraw(x,n): n-th power without reduction of the binary quadratic + form x. +Doc: $n$-th power of the binary quadratic form + $x$, computed without doing any \idx{reduction} (i.e.~using \kbd{qfbcompraw}). + Here $n$ must be nonnegative and $n<2^{31}$. + +Function: qfbprimeform +Class: basic +Section: number_theoretical +C-Name: primeform +Prototype: GG +Help: qfbprimeform(x,p): returns the prime form of discriminant x, whose + first coefficient is p. +Doc: prime binary quadratic form of discriminant + $x$ whose first coefficient is $p$, where $|p|$ is a prime number. + By abuse of notation, + $p = \pm 1$ is also valid and returns the unit form. Returns an + error if $x$ is not a quadratic residue mod $p$, or if $x < 0$ and $p < 0$. + (Negative definite \typ{QFB} are not implemented.) + +Function: qfbred +Class: basic +Section: number_theoretical +C-Name: qfbred0 +Prototype: GD0,L,DGDG +Help: qfbred(x,{flag=0},{isd},{sd}): reduction of the binary + quadratic form x. All other args. are optional. The argument isd and + sd, if present, supply the values of floor(sqrt(d)) and sqrt(d) + respectively, where d is the discriminant. If d<0, its value is not used. + flag can be any of 0: default; 1: do a single reduction step; +Doc: reduces the binary quadratic form $x$ (updating Shanks's distance + function $d$ if $x = [q,d]$ is an extended \emph{indefinite} form). + If $\fl$ is $1$, the function performs a single \idx{reduction} step, and + a complete reduction otherwise. + + The arguments \var{isd}, \var{sd}, if present, supply the values of + $\floor{\sqrt{D}}$, and $\sqrt{D}$ respectively, where $D$ + is the discriminant (this is not checked). + If $d < 0$ these values are useless. +Variant: Also available is \fun{GEN}{qfbred}{GEN x} (\fl is 0, \kbd{isd} + and \kbd{sd} are \kbd{NULL}) + +Function: qfbredsl2 +Class: basic +Section: number_theoretical +C-Name: qfbredsl2 +Prototype: GDG +Help: qfbredsl2(x,{isD}): reduction of the binary quadratic form x, returns + [y,g] where y is reduced and g in Sl(2,Z) is such that g.x = y; isD, if + present, must be equal to sqrtint(D), where D > 0 is the discriminant of x. +Doc: + reduction of the (real or imaginary) binary quadratic form $x$, returns + $[y,g]$ where $y$ is reduced and $g$ in $\text{SL}(2,\Z)$ is such that + $g \cdot x = y$; \var{isD}, if + present, must be equal to $\kbd{sqrtint}(D)$, where $D > 0$ is the + discriminant of $x$. + + The action of $g$ on $x$ can be computed using \kbd{qfeval(x,g)} + \bprog + ? q1 = Qfb(33947,-39899,11650); + ? [q2,U] = qfbredsl2(q1) + %2 = [Qfb(749,2207,-1712),[-1,3;-2,5]] + ? qfeval(q1,U) + %3 = Qfb(749,2207,-1712) + @eprog + +Function: qfbsolve +Class: basic +Section: number_theoretical +C-Name: qfbsolve +Prototype: GGD0,L, +Help: qfbsolve(Q,n,{flag=0}): Solve the equation + Q(x,y)=n in coprime integers x and y where Q is a binary quadratic form, + up to the action of the special orthogonal group of Q over the integers. + Binary digits of flag mean + 1: return all solutions, + 2: also include imprimitive solutions. +Doc: Solve the equation $Q(x,y)=n$ in coprime integers $x$ and $y$ (primitive + solutions), where + $Q$ is a binary quadratic form and $n$ an integer, up to the action of the + special orthogonal group $G=SO(Q,\Z)$, which is isomorphic to the group of + units of positive norm of the quadratic order of discriminant $D = \disc Q$. + If $D>0$, $G$ is infinite. If $D<-4$, $G$ is of order $2$, if $D=-3$, $G$ is + of order $6$ and if $D=-4$, $G$ is of order $4$. + + Binary digits of $\fl$ mean: + 1: return all solutions if set, else a single solution; return $[]$ if + a single solution is wanted (bit unset) but none exist. + 2: also include imprimitive solutions. + + When $\fl = 2$ (return a single solution, possibly imprimitive), the + algorithm returns a solution with minimal content; in particular, a + primitive solution exists if and only if one is returned. + + The integer $n$ can also be given by its factorization matrix + \kbd{\var{fa} = factor(n)} or by the pair $[n, \var{fa}]$. + + \bprog + ? qfbsolve(Qfb(1,0,2), 603) \\ a single primitive solution + %1 = [5, 17] + + ? qfbsolve(Qfb(1,0,2), 603, 1) \\ all primitive solutions + %2 = [[5, 17], [-19, -11], [19, -11], [5, -17]] + + ? qfbsolve(Qfb(1,0,2), 603, 2) \\ a single, possibly imprimitive solution + %3 = [5, 17] \\ actually primitive + + ? qfbsolve(Qfb(1,0,2), 603, 3) \\ all solutions + %4 = [[5, 17], [-19, -11], [19, -11], [5, -17], [-21, 9], [-21, -9]] + + ? N = 2^128+1; F = factor(N); + ? qfbsolve(Qfb(1,0,1),[N,F],1) + %3 = [[-16382350221535464479,8479443857936402504], + [18446744073709551616,-1],[-18446744073709551616,-1], + [16382350221535464479,8479443857936402504]] + @eprog + + For fixed $Q$, assuming the factorisation of $n$ is given, the algorithm + runs in probabilistic polynomial time in $\log p$, where $p$ is the largest + prime divisor of $n$, through the computation of square roots of $D$ modulo + $4\*p$). The dependency on $Q$ is more complicated: polynomial time in $\log + |D|$ if $Q$ is imaginary, but exponential time if $Q$ is real (through the + computation of a full cycle of reduced forms). In the latter case, note that + \tet{bnfisprincipal} provides a solution in heuristic subexponential time + assuming the GRH. + +Function: qfcholesky +Class: basic +Section: linear_algebra +C-Name: qfcholesky +Prototype: Gp +Help: qfcholesky(q): given a square symmetric matrix M, return R such that + R~*R = M, or [] if there is no solution. +Doc: given a square symmetric \typ{MAT} $M$, return $R$ such that + $^t{}R\*R = M$, or $[]$ if there is no solution. + +Function: qfcvp +Class: basic +Section: linear_algebra +C-Name: qfcvp0 +Prototype: GGDGDGD0,L, +Help: qfcvp(x,t,{B},{m},{flag=0}): x being a square and symmetric + matrix representing a positive definite quadratic form, and t a vector of + the same dimension, this function deals with the vectors of whose squared + distance to t is less than B, enumerated using the Fincke-Pohst algorithm, + storing at most m vectors (no limit if m is omitted). The function searches + for the closest vectors to t if B is omitted or <= 0. The precise behavior + depends on flag. 0: returns at most m vectors (unless m omitted), returns + [N,M,V] where N is the number of vectors enumerated, M the maximum squared + distance among these, and V lists the vectors. 1: ignores m and returns the + first vector whose squared distance to t is less than B. +Doc: $x$ being a square and symmetric matrix of dimension $d$ representing + a positive definite quadratic form, and $t$ a vector of the same dimension $d$. + This function deals with the vectors whose squared distance to $t$ is + less than $B$, enumerated using the Fincke-Pohst algorithm, storing at most + $m$ vectors. There is no limit if $m$ is omitted: beware that this may be a + huge vector! The vectors are returned in no particular order. + + The function searches for the closest vectors to $t$ if $B$ is omitted + or $\leq 0$. + The behavior is undefined if $x$ is not positive definite (a ``precision too + low'' error is most likely, although more precise error messages are + possible). The precise behavior depends on $\fl$. + + \item If $\fl=0$ (default), return $[N, M, V]$, where $N$ is the number of + vectors enumerated (possibly larger than $m$), $M \leq B$ is the maximum + squared distance found, and $V$ is a matrix whose columns are found vectors. + + \item If $\fl=1$, ignore $m$ and return $[M,v]$, where $v$ is a vector at + squared distance $M \leq B$. If no vector has distance $\leq B$, return $[]$. + + In these two cases, $x$ must have integral \emph{small} entries: more + precisely, we definitely must have $d\cdot \|x\|_\infty^2 < 2^{53}$ but + even that may not be enough. The implementation uses low precision floating + point computations for maximal speed and gives incorrect results when $x$ + has large entries. That condition is checked in the code and the routine + raises an error if large rounding errors occur. + + \bprog + ? M = [2,1;1,2]; t = [1/2, -1/2]; + ? qfcvp(M, t, 0) + %2 = [2, 0.5000000000000000000, [0, 1; 0, -1]] + ? qfcvp(M, t, 1.5) + %3 = [4, 1.5000000000000000000, [1, 0, 1, 0; 0, 0, -1, -1]] + @eprog + +Function: qfeval +Class: basic +Section: linear_algebra +C-Name: qfeval0 +Prototype: DGGDG +Help: qfeval({q},x,{y}): evaluate the quadratic form q (symmetric matrix) at x; + if y is present, evaluate the polar form at (x,y); + if q omitted, use the standard Euclidean form. +Doc: evaluate the quadratic form $q$ (given by a symmetric matrix) + at the vector $x$; if $y$ is present, evaluate the polar form at $(x,y)$; + if $q$ omitted, use the standard Euclidean scalar product, corresponding to + the identity matrix. + + Roughly equivalent to \kbd{x\til * q * y}, but a little faster and + more convenient (does not distinguish between column and row vectors): + \bprog + ? x = [1,2,3]~; y = [-1,3,1]~; q = [1,2,3;2,2,-1;3,-1,9]; + ? qfeval(q,x,y) + %2 = 23 + ? for(i=1,10^6, qfeval(q,x,y)) + time = 661ms + ? for(i=1,10^6, x~*q*y) + time = 697ms + @eprog\noindent The speedup is noticeable for the quadratic form, + compared to \kbd{x\til * q * x}, since we save almost half the + operations: + \bprog + ? for(i=1,10^6, qfeval(q,x)) + time = 487ms + @eprog\noindent The special case $q = \text{Id}$ is handled faster if we + omit $q$ altogether: + \bprog + ? qfeval(,x,y) + %6 = 8 + ? q = matid(#x); + ? for(i=1,10^6, qfeval(q,x,y)) + time = 529 ms. + ? for(i=1,10^6, qfeval(,x,y)) + time = 228 ms. + ? for(i=1,10^6, x~*y) + time = 274 ms. + @eprog + + We also allow \typ{MAT}s of compatible dimensions for $x$, + and return \kbd{x\til * q * x} in this case as well: + \bprog + ? M = [1,2,3;4,5,6;7,8,9]; qfeval(,M) \\ Gram matrix + %5 = + [66 78 90] + + [78 93 108] + + [90 108 126] + + ? q = [1,2,3;2,2,-1;3,-1,9]; + ? for(i=1,10^6, qfeval(q,M)) + time = 2,008 ms. + ? for(i=1,10^6, M~*q*M) + time = 2,368 ms. + + ? for(i=1,10^6, qfeval(,M)) + time = 1,053 ms. + ? for(i=1,10^6, M~*M) + time = 1,171 ms. + @eprog + + If $q$ is a \typ{QFB}, it is implicitly converted to the + attached symmetric \typ{MAT}. This is done more + efficiently than by direct conversion, since we avoid introducing a + denominator $2$ and rational arithmetic: + \bprog + ? q = Qfb(2,3,4); x = [2,3]; + ? qfeval(q, x) + %2 = 62 + ? Q = Mat(q) + %3 = + [ 2 3/2] + + [3/2 4] + ? qfeval(Q, x) + %4 = 62 + ? for (i=1, 10^6, qfeval(q,x)) + time = 758 ms. + ? for (i=1, 10^6, qfeval(Q,x)) + time = 1,110 ms. + @eprog + Finally, when $x$ is a \typ{MAT} with \emph{integral} coefficients, we allow + a \typ{QFB} for $q$ and return the binary + quadratic form $q \circ M$. Again, the conversion to \typ{MAT} is less + efficient in this case: + \bprog + ? q = Qfb(2,3,4); Q = Mat(q); x = [1,2;3,4]; + ? qfeval(q, x) + %2 = Qfb(47, 134, 96) + ? qfeval(Q,x) + %3 = + [47 67] + + [67 96] + ? for (i=1, 10^6, qfeval(q,x)) + time = 701 ms. + ? for (i=1, 10^6, qfeval(Q,x)) + time = 1,639 ms. + @eprog + +Function: qfgaussred +Class: basic +Section: linear_algebra +C-Name: qfgaussred0 +Prototype: GD0,L, +Help: qfgaussred(q,{flag=0}): square reduction of the symmetric matrix q. + flag=0: returns a square matrix A such that q(x) = sum_i A[i,i] (x[i] + + sum_{j != i} A[i,j] x[j])^2; flag=1 return [U,V] where U is a square matrix + and V a vector such that q = U~ * matdiagonal(V) * U +Doc: + \idx{decomposition into squares} of the + quadratic form represented by the symmetric matrix $q$. If $\fl=0$ (default), + the result is a matrix $M$ whose diagonal entries are the coefficients of the + squares, and the off-diagonal entries on each line represent the bilinear + forms. More precisely, if $(a_{ij})$ denotes the output, one has + $$ q(x) = \sum_{i} a_{i,i} (x_{i} + \sum_{j \neq i} a_{i,j} x_{j})^{2} $$ + \bprog + ? qfgaussred([0,1;1,0]) + %1 = + [1/2 1] + + [-1 -1/2] + @eprog\noindent This means that $2xy = (1/2)(x+y)^{2} - (1/2)(x-y)^{2}$. + Singular matrices are supported, in which case some diagonal coefficients + vanish: + \bprog + ? qfgaussred([1,1;1,1]) + %2 = + [1 1] + + [1 0] + @eprog\noindent This means that $x^{2} + 2xy + y^{2} = (x+y)^{2}$. + + If $\fl=1$, return \kbd{[U,V]} where $U$ is a square matrix and $V$ a vector, + such that if \kbd{D=matdiagonal(V)}, $q = {^{t}} U D U$. More + precisely + $$ q(x) = \sum_{i} D_{i} (\sum_{j} U_{i,j} x_{j})^{2} $$ + and the matrix $M$ is recovered as $M = U + D - 1$. + \bprog + ? q = [0,1;1,0]; + ? [U,V] = qfgaussred(q,1); D = matdiagonal(V); + ? U~*D*U + %5 = + [0 1] + + [1 0] + ? U+D-1 + %6 = + [1/2 1] + + [ -1 -1/2] + @eprog +Variant: See also the functions \fun{GEN}{qfgaussred}{GEN a} + (for \kbd{qfgaussred(a,0)}), + \fun{GEN}{qfgaussred2}{GEN a} (for \kbd{qfgaussred0(a,1)}). Finally, + the function + \fun{GEN}{qfgaussred_positive}{GEN q} assumes that $q$ is + positive definite and is a little faster; returns \kbd{NULL} if a vector + with negative norm occurs (non positive matrix or too many rounding errors). + +Function: qfisom +Class: basic +Section: linear_algebra +C-Name: qfisom0 +Prototype: GGDGDG +Help: qfisom(G,H,{fl},{grp}): find an isomorphism between the integral positive + definite quadratic forms G and H if it exists. G can also be given by a + qfisominit structure which is preferable if several forms need to be compared + to G. +Doc: + $G$, $H$ being square and symmetric matrices with integer entries representing + positive definite quadratic forms, return an invertible matrix $S$ such that + $G={^{t}}S\*H\*S$. This defines a isomorphism between the corresponding lattices. + Since this requires computing the minimal vectors, the computations can + become very lengthy as the dimension grows. + See \kbd{qfisominit} for the meaning of \var{fl}. + If \var{grp} is given it must be the automorphism group of $H$. It will be used + to speed up the computation. + + $G$ can also be given by an \kbd{qfisominit} structure which is preferable if + several forms $H$ need to be compared to $G$. + + This function implements an algorithm of Plesken and Souvignier, following + Souvignier's implementation. +Variant: Also available is \fun{GEN}{qfisom}{GEN G, GEN H, GEN fl, GEN grp} + where $G$ is a vector of \kbd{zm}, and $H$ is a \kbd{zm}, and $grp$ is + either \kbd{NULL} or a vector of \kbd{zm}. + +Function: qfisominit +Class: basic +Section: linear_algebra +C-Name: qfisominit0 +Prototype: GDGDG +Help: qfisominit(G,{fl},{m}): G being a square and symmetric matrix representing an + integral positive definite quadratic form, this function returns a structure + allowing to compute isomorphisms between G and other quadratic form faster. +Doc: + $G$ being a square and symmetric matrix with integer entries representing a + positive definite quadratic form, return an \kbd{isom} structure allowing to + compute isomorphisms between $G$ and other quadratic forms faster. + + The interface of this function is experimental and will likely change in future + release. + + If present, the optional parameter \var{fl} must be a \typ{VEC} with two + components. It allows to specify the invariants used, which can make the + computation faster or slower. The components are + + \item \kbd{fl[1]} Depth of scalar product combination to use. + + \item \kbd{fl[2]} Maximum level of Bacher polynomials to use. + + If present, $m$ must be the set of vectors of norm up to the maximal of the + diagonal entry of $G$, either as a matrix or as given by \kbd{qfminim}. + Otherwise this function computes the minimal vectors so it become very + lengthy as the dimension of $G$ grows. +Variant: Also available is + \fun{GEN}{qfisominit}{GEN F, GEN fl} + where $F$ is a vector of \kbd{zm}. + +Function: qfjacobi +Class: basic +Section: linear_algebra +C-Name: jacobi +Prototype: Gp +Help: qfjacobi(A): eigenvalues and orthogonal matrix of eigenvectors of the + real symmetric matrix A. +Doc: apply Jacobi's eigenvalue algorithm to the real symmetric matrix $A$. + This returns $[L, V]$, where + + \item $L$ is the vector of (real) eigenvalues of $A$, sorted in increasing + order, + + \item $V$ is the corresponding orthogonal matrix of eigenvectors of $A$. + + \bprog + ? \p19 + ? A = [1,2;2,1]; mateigen(A) + %1 = + [-1 1] + + [ 1 1] + ? [L, H] = qfjacobi(A); + ? L + %3 = [-1.000000000000000000, 3.000000000000000000]~ + ? H + %4 = + [ 0.7071067811865475245 0.7071067811865475244] + + [-0.7071067811865475244 0.7071067811865475245] + ? norml2( (A-L[1])*H[,1] ) \\ approximate eigenvector + %5 = 9.403954806578300064 E-38 + ? norml2(H*H~ - 1) + %6 = 2.350988701644575016 E-38 \\ close to orthogonal + @eprog + +Function: qflll +Class: basic +Section: linear_algebra +C-Name: qflll0 +Prototype: GD0,L, +Help: qflll(x,{flag=0}): LLL reduction of the vectors forming the matrix x + (gives the unimodular transformation matrix T such that x*T is LLL-reduced). + flag is optional, and can be 0: default, 1: disable FLATTER, 2: assumes x + is integral, returns a partially reduced basis, 3: assumes x is integral, in + place (return x*T), 4: assumes x is integral, returns [K,T] where K is the + integer kernel of x and T the LLL reduced image, 5: same as 4 but x may have + polynomial coefficients, 8: same as 0 but x may have polynomial coefficients. +Description: + (vec, ?0):vec lll($1) + (vec, 2):vec lllintpartial($1) + (vec, 4):vec lllkerim($1) + (vec, 5):vec lllkerimgen($1) + (vec, 8):vec lllgen($1) + (vec, #small):vec $"Bad flag in qflll" + (vec, small):vec qflll0($1, $2) +Doc: \idx{LLL} algorithm applied to the + \emph{columns} of the matrix $x$. The columns of $x$ may be linearly + dependent. The result is by default a unimodular transformation matrix $T$ + such that $x \cdot T$ is an LLL-reduced basis of the lattice generated by + the column vectors of $x$. Note that if $x$ is not of maximal rank $T$ will + not be square. The LLL parameters are $(0.51,0.99)$, meaning that the + Gram-Schmidt coefficients for the final basis satisfy $|\mu_{i,j}| \leq + 0.51$, and the Lov\'{a}sz's constant is $0.99$. + + If $\fl=0$ (default), assume that $x$ has either exact (integral or + rational) or real floating point entries. The matrix is rescaled, converted + to integers and the behavior is then as in $\fl = 1$. + Computations involving Gram-Schmidt + vectors are approximate, with precision varying as needed (Lehmer's trick, + as generalized by Schnorr). Adapted from Nguyen and Stehl\'e's algorithm + and Stehl\'e's code (\kbd{fplll-1.3}) as building blocks for the FLATTER + (block recursive) algorithm of Heninger and Ryan. + + If $\fl=1$, disable use of FLATTER algorithm; use \kbd{fplll}. This flag + is provided to experiment with the concrete speed-ups allowed by FLATTER, + as well as to genuinely disable it on the rare classes of lattices for which + it turns out it performs badly: many such classes are detected in the code, + which then restricts to stock \kbd{fplll}, but new exemples may turn up. + + If $\fl=2$, $x$ should be an integer matrix whose columns are linearly + independent. Returns a partially reduced basis for $x$, using an unpublished + algorithm by Peter Montgomery: a basis is said to be \emph{partially reduced} + if $|v_{i} \pm v_{j}| \geq |v_{i}|$ for any two distinct basis vectors + $v_{i}, \, v_{j}$. This is faster than $\fl=1$, esp. when one row is huge + compared + to the other rows (knapsack-style), and should quickly produce relatively + short vectors. The resulting basis is \emph{not} LLL-reduced in general. + If LLL reduction is eventually desired, avoid this partial reduction: + applying LLL to the partially reduced matrix is significantly \emph{slower} + than starting from a knapsack-type lattice. + + If $\fl=3$, as $\fl=0$, but the reduction is performed in place: the + routine returns $x \cdot T$. This is usually faster for knapsack-type + lattices. + + If $\fl=4$, as $\fl=0$, returning a vector $[K, T]$ of matrices: the + columns of $K$ represent a basis of the integer kernel of $x$ + (not LLL-reduced in general) and $T$ is the transformation + matrix such that $x\cdot T$ is an LLL-reduced $\Z$-basis of the image + of the matrix $x$. + + If $\fl=5$, case as $\fl=4$, but $x$ may have polynomial coefficients. + + If $\fl=8$, same as $\fl=0$, but $x$ may have polynomial coefficients. + + \bprog + ? \p500 + realprecision = 500 significant digits + ? a = 2*cos(2*Pi/97); + ? C = 10^450; + ? v = powers(a,48); b = round(matconcat([matid(48),C*v]~)); + ? p = b * qflll(b)[,1]; \\ tiny linear combination of powers of 'a' + time = 4,470 ms. + ? exponent(v * p / C) + %5 = -1418 + ? p3 = qflll(b,3)[,1]; \\ compute in place, faster + time = 3,790 ms. + ? p3 == p \\ same result + %7 = 1 + ? p2 = b * qflll(b,2)[,1]; \\ partial reduction: faster, not as good + time = 343 ms. + ? exponent(v * p2 / C) + %9 = -1190 + @eprog +Variant: Also available are \fun{GEN}{lll}{GEN x} ($\fl=0$), + \fun{GEN}{lllint}{GEN x} ($\fl=1$), and \fun{GEN}{lllkerim}{GEN x} ($\fl=4$). + +Function: qflllgram +Class: basic +Section: linear_algebra +C-Name: qflllgram0 +Prototype: GD0,L, +Help: qflllgram(G,{flag=0}): LLL reduction of the lattice whose gram matrix + is G (gives the unimodular transformation matrix). flag is optional and can + be 0: default,1: disable FLATTER, 4: assumes x is integral, + returns [K,T], where K is the integer kernel of x + and T the LLL reduced image, 5: same as 4 but x may have polynomial + coefficients, 8: same as 0 but x may have polynomial coefficients. +Doc: same as \kbd{qflll}, except that the + matrix $G = \kbd{x\til * x}$ is the Gram matrix of some lattice vectors $x$, + and not the coordinates of the vectors themselves. In particular, $G$ must + now be a square symmetric real matrix, corresponding to a positive + quadratic form (not necessarily definite: $x$ needs not have maximal rank). + The result is a unimodular + transformation matrix $T$ such that $x \cdot T$ is an LLL-reduced basis of + the lattice generated by the column vectors of $x$. See \tet{qflll} for + further details about the LLL implementation. + + If $\fl=0$ (default), assume that $G$ has either exact (integral or + rational) or real floating point entries. The matrix is rescaled, converted + to integers. + Computations involving Gram-Schmidt vectors are approximate, with precision + varying as needed (Lehmer's trick, as generalized by Schnorr). Adapted from + Nguyen and Stehl\'e's algorithm and Stehl\'e's code (\kbd{fplll-1.3}) and + FLATTER algorithm for Heninger and Ryan. + + If $\fl=1$, disable use of FLATTER algorithm. + + $\fl=4$: $G$ has integer entries, gives the kernel and reduced image of $x$. + + $\fl=5$: same as $4$, but $G$ may have polynomial coefficients. +Variant: Also available are \fun{GEN}{lllgram}{GEN G} ($\fl=0$), + \fun{GEN}{lllgramint}{GEN G} ($\fl=1$), and \fun{GEN}{lllgramkerim}{GEN G} + ($\fl=4$). + +Function: qfminim +Class: basic +Section: linear_algebra +C-Name: qfminim0 +Prototype: GDGDGD0,L,p +Help: qfminim(x,{B},{m},{flag=0}): x being a square and symmetric + matrix representing a positive definite quadratic form, this function + deals with the vectors of x whose norm is less than or equal to B, + enumerated using the Fincke-Pohst algorithm, storing at most m vectors (no + limit if m is omitted). The function searches for + the minimal nonzero vectors if B is omitted. The precise behavior + depends on flag. 0: returns at most 2m vectors (unless m omitted), returns + [N,M,V] where N is the number of vectors enumerated, M the maximum norm among + these, and V lists half the vectors (the other half is given by -V). 1: + ignores m and returns the first vector whose norm is less than B. 2: as 0 + but uses a more robust, slower implementation +Doc: $x$ being a square and symmetric matrix of dimension $d$ representing + a positive definite quadratic form, this function deals with the vectors of + $x$ whose norm is less than or equal to $B$, enumerated using the + Fincke-Pohst algorithm, storing at most $m$ pairs of vectors: only one + vector is given for each pair $\pm v$. There is no limit if $m$ is omitted: + beware that this may be a huge vector! The vectors are returned in no + particular order. + + The function searches for the minimal nonzero vectors if $B$ is omitted. + The behavior is undefined if $x$ is not positive definite (a ``precision too + low'' error is most likely, although more precise error messages are + possible). The precise behavior depends on $\fl$. + + \item If $\fl=0$ (default), return $[N, M, V]$, where $N$ is the number of + vectors enumerated (an even number, possibly larger than $2m$), $M \leq B$ + is the maximum norm found, and $V$ is a matrix whose columns are found + vectors. + + \item If $\fl=1$, ignore $m$ and return $[M,v]$, where $v$ is a nonzero + vector of length $M \leq B$. If no nonzero vector has length $\leq B$, + return $[]$. If no explicit $B$ is provided, return a vector of smallish + norm, namely the vector of smallest length (usually the first one but not + always) in an LLL-reduced basis for $x$. + + In these two cases, $x$ must have integral \emph{small} entries: more + precisely, we definitely must have $d\cdot \|x\|_{\infty}^{2} < 2^{53}$ but + even that may not be enough. The implementation uses low precision floating + point computations for maximal speed and gives incorrect results when $x$ + has large entries. That condition is checked in the code and the routine + raises an error if large rounding errors occur. A more robust, but much + slower, implementation is chosen if the following flag is used: + + \item If $\fl=2$, $x$ can have non integral real entries, but this is also + useful when $x$ has large integral entries. Return $[N, M, V]$ as in case + $\fl = 0$, where $M$ is returned as a floating point number. If $x$ is + inexact and $B$ is omitted, the ``minimal'' vectors in $V$ only have + approximately the same norm (up to the internal working accuracy). + This version is very robust but still offers no hard and fast guarantee + about the result: it involves floating point operations performed at a high + floating point precision depending on your input, but done without rigorous + tracking of roundoff errors (as would be provided by interval arithmetic for + instance). No example is known where the input is exact but the function + returns a wrong result. + + \bprog + ? x = matid(2); + ? qfminim(x) \\@com 4 minimal vectors of norm 1: $\pm[0,1]$, $\pm[1,0]$ + %2 = [4, 1, [0, 1; 1, 0]] + ? { x = \\ The Leech lattice + [4, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1, 0,-1, 0, 0, 0,-2; + 2, 4,-2,-2, 0,-2, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1, 0, 1,-1,-1; + 0,-2, 4, 0,-2, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 0, 0, 1,-1,-1, 0, 0; + 0,-2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1,-1, 0, 1,-1, 1, 0; + 0, 0,-2, 0, 4, 0, 0, 0, 1,-1, 0, 0, 1, 0, 0, 0,-2, 0, 0,-1, 1, 1, 0, 0; + -2, -2,0, 0, 0, 4,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,-1, 1, 1; + 0, 0, 0, 0, 0,-2, 4,-2, 0, 0, 0, 0, 0, 1, 0, 0, 0,-1, 0, 0, 0, 1,-1, 0; + 0, 0, 0, 0, 0, 0,-2, 4, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1,-1,-1, 0, 1, 0; + 0, 0, 0, 0, 1,-1, 0, 0, 4, 0,-2, 0, 1, 1, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0; + 0, 0, 0, 0,-1, 0, 0, 0, 0, 4, 0, 0, 1, 1,-1, 1, 0, 0, 0, 1, 0, 0, 1, 0; + 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 4,-2, 0,-1, 0, 0, 0,-1, 0,-1, 0, 0, 0, 0; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 4,-1, 1, 0, 0,-1, 1, 0, 1, 1, 1,-1, 0; + 1, 0,-1, 1, 1, 0, 0,-1, 1, 1, 0,-1, 4, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1,-1; + -1,-1, 1,-1, 0, 0, 1, 0, 1, 1,-1, 1, 0, 4, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1; + 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 1, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0; + 0, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 1, 0, 4, 0, 0, 0, 0, 1, 1, 0, 0; + 0, 0, 1, 0,-2, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 4, 1, 1, 1, 0, 0, 1, 1; + 1, 0, 0, 1, 0, 0,-1, 0, 1, 0,-1, 1, 1, 0, 0, 0, 1, 4, 0, 1, 1, 0, 1, 0; + 0, 0, 0,-1, 0, 1, 0,-1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 4, 0, 1, 1, 0, 1; + -1, -1,1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0, 1, 0, 0, 1, 1, 0, 4, 0, 0, 1, 1; + 0, 0,-1, 1, 1, 0, 0,-1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 4, 1, 0, 1; + 0, 1,-1,-1, 1,-1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 4, 0, 1; + 0,-1, 0, 1, 0, 1,-1, 1, 0, 1, 0,-1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 4, 1; + -2,-1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 4]; } + ? qfminim(x,,0) \\ 0: don't store minimal vectors + time = 121 ms. + %4 = [196560, 4, [;]] \\ 196560 minimal vectors of norm 4 + ? qfminim(x) \\ store all minimal vectors ! + time = 821 ms. + ? qfminim(x,,0,2); \\ safe algorithm. Slower and unnecessary here. + time = 5,540 ms. + %6 = [196560, 4.000061035156250000, [;]] + ? qfminim(x,,,2); \\ safe algorithm; store all minimal vectors + time = 6,602 ms. + @eprog\noindent\sidx{Leech lattice}\sidx{minimal vector} + In this example, storing 0 vectors limits memory use; storing all of them + requires a \kbd{parisize} about 50MB. All minimal vectors are nevertheless + enumerated in both cases of course, which means the speedup is likely to be + marginal. +Variant: Also available are + \fun{GEN}{minim}{GEN x, GEN B = NULL, GEN m = NULL} ($\fl=0$), + \fun{GEN}{minim2}{GEN x, GEN B = NULL, GEN m = NULL} ($\fl=1$). + \fun{GEN}{minim_raw}{GEN x, GEN B = NULL, GEN m = NULL} (do not perform LLL + reduction on x and return \kbd{NULL} on accuracy error). + \fun{GEN}{minim_zm}{GEN x, GEN B = NULL, GEN m = NULL} ($\fl=0$, return vectors as + \typ{VECSMALL} to save memory) + +Function: qfminimize +Class: basic +Section: linear_algebra +C-Name: qfminimize +Prototype: G +Help: qfminimize(G): given a square symmetric matrix G with rational + coefficients and non-zero determinant, of dimension n >= 1, return [H,U,c] + such that H = c * U~*G*U for some rational c, and H integral with minimal + determinant. +Doc: Given a square symmetric matrix $G$ with rational coefficients, and + non-zero determinant, of dimension $n \geq 1$, return \kbd{[H,U,c]} such that + \kbd{H = c*U\til*G*U} for some rational $c$, and $H$ integral with minimal + determinant. The coefficients of $U$ are usually nonintegral. + \bprog + ? G = matdiagonal([650, -104329, -104329]); + ? [H,U,c]=qfminimize(G); H + %2 = [-1,0,0;0,-1,0;0,0,1] + ? U + %3 = [0,0,1/5;5/323,-1/323,0;-1/323,-5/323,0] + ? c + %4 = 1/26 + ? c * U~ * G * U + %4 = [-1,0,0;0,-1,0;0,0,1] + @eprog + +Function: qfnorm +Class: basic +Section: linear_algebra +C-Name: qfnorm +Prototype: GDG +Obsolete: 2016-08-08 +Help: qfnorm(x,{q}): this function is obsolete, use qfeval. +Doc: this function is obsolete, use \kbd{qfeval}. + +Function: qforbits +Class: basic +Section: linear_algebra +C-Name: qforbits +Prototype: GG +Help: qforbits(G,V): return the orbits of V under the action of the group + of linear transformation generated by the set G, which must stabilize V. +Doc: return the orbits of $V$ under the action of the group + of linear transformation generated by the set $G$. + It is assumed that $G$ contains minus identity, and only one vector + in $\{v, -v\}$ should be given. + If $G$ does not stabilize $V$, the function return $0$. + + In the example below, we compute representatives and lengths of the orbits of + the vectors of norm $\leq 3$ under the automorphisms of the lattice $\Z^{6}$. + \bprog + ? Q=matid(6); G=qfauto(Q); V=qfminim(Q,3); + ? apply(x->[x[1],#x],qforbits(G,V)) + %2 = [[[0,0,0,0,0,1]~,6],[[0,0,0,0,1,-1]~,30],[[0,0,0,1,-1,-1]~,80]] + @eprog + +Function: qfparam +Class: basic +Section: linear_algebra +C-Name: qfparam +Prototype: GGD0,L, +Help: qfparam(G,sol,{flag=0}): + coefficients of binary quadratic forms that parametrize the + solutions of the ternary quadratic form G, using the particular + solution sol. +Doc: coefficients of binary quadratic forms that parametrize the + solutions of the ternary quadratic form $G$, using the particular + solution~\var{sol}. + $\fl$ is optional and can be 1, 2, or 3, in which case the $\fl$-th form is + reduced. The default is $\fl=0$ (no reduction). + \bprog + ? G = [1,0,0;0,1,0;0,0,-34]; + ? M = qfparam(G, qfsolve(G)) + %2 = + [ 3 -10 -3] + + [-5 -6 5] + + [ 1 0 1] + @eprog + Indeed, the solutions can be parametrized as + $$(3x^{2}-10xy-3y^{2})^{2} + (-5x^{2}-6xy+5y^{2})^{2} -34(x^{2}+y^{2})^{2} + = 0.$$ + \bprog + ? v = y^2 * M*[1,x/y,(x/y)^2]~ + %3 = [3*x^2 - 10*y*x - 3*y^2, -5*x^2 - 6*y*x + 5*y^2, -x^2 - y^2]~ + ? v~*G*v + %4 = 0 + @eprog + +Function: qfperfection +Class: basic +Section: linear_algebra +C-Name: qfperfection +Prototype: G +Help: qfperfection(G): rank of matrix of xx~ for x minimal vectors of a Gram + matrix G. +Doc: $G$ being a square and symmetric matrix with integer entries + representing a positive definite quadratic form, outputs the perfection rank + of the form. That is, gives the rank of the family of the $s$ symmetric + matrices $v{^{t}}v$, where $v$ runs through the minimal vectors. + + A form is perfect if and only if its perfection rank is $d(d+1)/2$ where + $d$ is the dimension of $G$. + + The algorithm computes the minimal vectors and its runtime is exponential + in $d$. + +Function: qfrep +Class: basic +Section: linear_algebra +C-Name: qfrep0 +Prototype: GGD0,L, +Help: qfrep(q,B,{flag=0}): vector of (half) the number of vectors of norms + from 1 to B for the integral and definite quadratic form q. If flag is 1, + count vectors of even norm from 1 to 2B. +Doc: + $q$ being a square and symmetric matrix with integer entries representing a + positive definite quadratic form, count the vectors representing successive + integers. + + \item If $\fl = 0$, count all vectors. Outputs the vector whose $i$-th + entry, $1 \leq i \leq B$ is half the number of vectors $v$ such that $q(v)=i$. + + \item If $\fl = 1$, count vectors of even norm. Outputs the vector + whose $i$-th entry, $1 \leq i \leq B$ is half the number of vectors such + that $q(v) = 2i$. + + \bprog + ? q = [2, 1; 1, 3]; + ? qfrep(q, 5) + %2 = Vecsmall([0, 1, 2, 0, 0]) \\ 1 vector of norm 2, 2 of norm 3, etc. + ? qfrep(q, 5, 1) + %3 = Vecsmall([1, 0, 0, 1, 0]) \\ 1 vector of norm 2, 0 of norm 4, etc. + @eprog\noindent + This routine uses a naive algorithm based on \tet{qfminim}, and + will fail if any entry becomes larger than $2^{31}$ (or $2^{63}$). + +Function: qfsign +Class: basic +Section: linear_algebra +C-Name: qfsign +Prototype: G +Help: qfsign(x): signature of the symmetric matrix x. +Doc: + returns $[p,m]$ the signature of the quadratic form represented by the + symmetric matrix $x$. Namely, $p$ (resp.~$m$) is the number of positive + (resp.~negative) eigenvalues of $x$. The result is computed using Gaussian + reduction. + +Function: qfsolve +Class: basic +Section: linear_algebra +C-Name: qfsolve +Prototype: G +Help: qfsolve(G): solve over Q the quadratic equation X~ G X = 0, where + G is a symmetric matrix. +Doc: Given a square symmetric matrix $G$ of dimension $n \geq 1$, solve over + $\Q$ the quadratic equation ${^{t}}X G X = 0$. The matrix $G$ must have rational + coefficients. When $G$ is integral, the argument can also be a vector $[G,F]$ + where $F$ is the factorization matrix of the absolute value of the determinant + of $G$. + + The solution might be a single nonzero column vector + (\typ{COL}) or a matrix (whose columns generate a totally isotropic + subspace). + + If no solution exists, returns an integer, that can be a prime $p$ such that + there is no local solution at $p$, or $-1$ if there is no real solution, + or $-2$ if $n = 2$ and $-\det G$ is not a square (which implies there is a + real solution, but no local solution at some $p$ dividing $\det G$). + \bprog + ? G = [1,0,0;0,1,0;0,0,-34]; + ? qfsolve(G) + %1 = [-3, -5, 1]~ + ? qfsolve([1,0; 0,2]) + %2 = -1 \\ no real solution + ? qfsolve([1,0,0;0,3,0; 0,0,-2]) + %3 = 3 \\ no solution in Q_3 + ? qfsolve([1,0; 0,-2]) + %4 = -2 \\ no solution, n = 2 + @eprog + +Function: quadclassunit +Class: basic +Section: number_theoretical +C-Name: quadclassunit0 +Prototype: GD0,L,DGp +Help: quadclassunit(D,{flag=0},{tech=[]}): compute the structure of the + class group and the regulator of the quadratic field of discriminant D. + See manual for the optional technical parameters. +Doc: \idx{Buchmann-McCurley}'s sub-exponential algorithm for computing the + class group of a quadratic order of discriminant $D$. By default, the + results are conditional on the GRH. + + This function should be used instead of \tet{qfbclassno} or + \tet{quadregulator} + when $D<-10^{25}$, $D>10^{10}$, or when the \emph{structure} is wanted. It + is a special case of \tet{bnfinit}, which is slower, but more robust. + + The result is a vector $v$ whose components should be accessed using + member functions: + + \item \kbd{$v$.no}: the class number + + \item \kbd{$v$.cyc}: a vector giving the structure of the class group as a + product of cyclic groups; + + \item \kbd{$v$.gen}: a vector giving generators of those cyclic groups (as + binary quadratic forms). + + \item \kbd{$v$.reg}: the regulator, computed to an accuracy which is the + maximum of an internal accuracy determined by the program and the current + default (note that once the regulator is known to a small accuracy it is + trivial to compute it to very high accuracy, see the tutorial). + + \item \kbd{$v$.normfu} (for positive $D$ only) return the norm of the + fundamental unit, either $1$ or $-1$. Note that a result of $-1$ is + unconditional and no longer depends on the GRH. + + The $\fl$ is obsolete and should be left alone. In older versions, + it supposedly computed the narrow class group when $D>0$, but this did not + work at all; use the general function \tet{bnfnarrow}. + + Optional parameter \var{tech} is a row vector of the form $[c_{1}, c_{2}]$, + where $c_{1} \leq c_{2}$ are nonnegative real numbers which control the execution + time and the stack size, see \ref{se:GRHbnf}. The parameter is used as a + threshold to balance the relation finding phase against the final linear + algebra. Increasing the default $c_{1}$ means that relations are easier + to find, but more relations are needed and the linear algebra will be + harder. The default value for $c_{1}$ is $0$ and means that it is taken equal + to $c_{2}$. The parameter $c_{2}$ is mostly obsolete and should not be changed, + but we still document it for completeness: we compute a tentative class + group by generators and relations using a factorbase of prime ideals + $\leq c_{1} (\log |D|)^{2}$, then prove that ideals of norm + $\leq c_{2} (\log |D|)^{2}$ do + not generate a larger group. By default an optimal $c_{2}$ is chosen, so that + the result is provably correct under the GRH --- a result of Greni\'e + and Molteni states that $c_{2} = 23/6 \approx 3.83$ is fine (and even + $c_{2} = 15/4 \approx 3.75$ for large $|D| > 2.41 E8$). But it is possible + to improve on this algorithmically. You may provide a smaller $c_{2}$, it will + be ignored (we use the provably correct one); you may provide a larger $c_{2}$ + than the default value, which results in longer computing times for equally + correct outputs (under GRH). +Variant: If you really need to experiment with the \var{tech} parameter, + it will be more convenient to use + \fun{GEN}{Buchquad}{GEN D, double c1, double c2, long prec}. + +Function: quaddisc +Class: basic +Section: number_theoretical +C-Name: quaddisc +Prototype: G +Help: quaddisc(x): discriminant of the quadratic field Q(sqrt(x)). +Doc: discriminant of the \'etale algebra $\Q(\sqrt{x})$, where $x\in\Q^{*}$. + This is the same as \kbd{coredisc}$(d)$ where $d$ is the integer + squarefree part of $x$, so $x=d f^{2}$ with $f\in \Q^{*}$ and $d\in\Z$. + This returns $0$ for $x = 0$, $1$ for $x$ square and the discriminant of + the quadratic field $\Q(\sqrt{x})$ otherwise. + \bprog + ? quaddisc(7) + %1 = 28 + ? quaddisc(-7) + %2 = -7 + @eprog + +Function: quadgen +Class: basic +Section: number_theoretical +C-Name: quadgen0 +Prototype: GDn +Help: quadgen(D,{v = 'w}): standard generator g of quadratic order of + discriminant D. If v is given, the variable name is used to display g, + else 'w' is used. +Doc: creates the quadratic number\sidx{omega} $\omega=(a+\sqrt{D})/2$ where + $a=0$ if $D\equiv0\mod4$, + $a=1$ if $D\equiv1\mod4$, so that $(1,\omega)$ is an integral basis for the + quadratic order of discriminant $D$. $D$ must be an integer congruent to 0 or + 1 modulo 4, which is not a square. + If \var{v} is given, the variable name is used to display $g$ else 'w' is used. + + \bprog + ? w = quadgen(5, 'w); w^2 - w - 1 + %1 = 0 + ? w = quadgen(0, 'w) + *** at top-level: w=quadgen(0) + *** ^---------- + *** quadgen: domain error in quadpoly: issquare(disc) = 1 + @eprog +Variant: + When \var{v} does not matter, the function + \fun{GEN}{quadgen}{GEN D} is also available. + +Function: quadhilbert +Class: basic +Section: number_theoretical +C-Name: quadhilbert +Prototype: Gp +Help: quadhilbert(D): relative equation for the Hilbert class field + of the quadratic field of discriminant D (which can also be a bnf). +Doc: relative equation defining the + \idx{Hilbert class field} of the quadratic field of discriminant $D$. + + If $D < 0$, uses complex multiplication (\idx{Schertz}'s variant). + + If $D > 0$ \idx{Stark units} are used and (in rare cases) a + vector of extensions may be returned whose compositum is the requested class + field. See \kbd{bnrstark} for details. + +Function: quadpoly +Class: basic +Section: number_theoretical +C-Name: quadpoly0 +Prototype: GDn +Help: quadpoly(D,{v='x}): quadratic polynomial corresponding to the + discriminant D, in variable v. +Doc: creates the ``canonical'' quadratic + polynomial (in the variable $v$) corresponding to the discriminant $D$, + i.e.~the minimal polynomial of $\kbd{quadgen}(D)$. $D$ must be an integer + congruent to 0 or 1 modulo 4, which is not a square. + + \bprog + ? quadpoly(5,'y) + %1 = y^2 - y - 1 + ? quadpoly(0,'y) + *** at top-level: quadpoly(0,'y) + *** ^-------------- + *** quadpoly: domain error in quadpoly: issquare(disc) = 1 + @eprog + +Function: quadray +Class: basic +Section: number_theoretical +C-Name: quadray +Prototype: GGp +Help: quadray(D,f): relative equation for the ray class field of + conductor f for the quadratic field of discriminant D (which can also be a + bnf). +Doc: relative equation for the ray + class field of conductor $f$ for the quadratic field of discriminant $D$ + using analytic methods. A \kbd{bnf} for $x^{2} - D$ is also accepted in place + of $D$. + + For $D < 0$, uses the $\sigma$ function and Schertz's method. + + For $D>0$, uses Stark's conjecture, and a vector of relative equations may be + returned. See \tet{bnrstark} for more details. + +Function: quadregulator +Class: basic +Section: number_theoretical +C-Name: quadregulator +Prototype: Gp +Help: quadregulator(D): regulator of the real quadratic field of + discriminant D. +Doc: regulator of the quadratic order of positive discriminant $D$ in time + $\tilde{O}(D^{1/2})$ using the continued fraction algorithm. Raise + an error if $D$ is not a discriminant (fundamental or not) or if $D$ is a + square. The function \kbd{quadclassunit} is asymptotically faster (and also + in practice for $D > 10^{10}$ or so) but depends on the GRH. + +Function: quadunit +Class: basic +Section: number_theoretical +C-Name: quadunit0 +Prototype: GDn +Help: quadunit(D,{v = 'w}): fundamental unit u of the quadratic order of + discriminant D where D must be positive. + If v is given, the variable name is used to display u, else 'w' is used. +Doc: a fundamental unit\sidx{fundamental units} $u$ of the real quadratic order + of discriminant $D$. The integer $D$ must be congruent to 0 or 1 modulo 4 + and not a square; the result is a quadratic number (see \secref{se:quadgen}). + If $D$ is not a fundamental discriminant, the algorithm is wasteful: if $D = + df^{2}$ with $d$ fundamental, it will be faster to compute \kbd{quadunit}$(d)$ + then raise it to the power \kbd{quadunitindex}$(d,f)$; or keep it in + factored form. + + If \var{v} is given, the variable name is used to display $u$ + else 'w' is used. The algorithm computes the continued fraction + of $(1 + \sqrt{D}) / 2$ or $\sqrt{D}/2$ (see GTM 138, algorithm 5.7.2). + Although the continued fraction length is only $O(\sqrt{D})$, + the function still runs in time $\tilde{O}(D)$, in part because the + output size is not polynomially bounded in terms of $\log D$. + See \kbd{bnfinit} and \kbd{bnfunits} for a better alternative for large + $D$, running in time subexponential in $\log D$ and returning the + fundamental units in compact form (as a short list of $S$-units of size + $O(\log D)^{3}$ raised to possibly large exponents). +Variant: + When \var{v} does not matter, the function + \fun{GEN}{quadunit}{GEN D} is also available. + +Function: quadunitindex +Class: basic +Section: number_theoretical +C-Name: quadunitindex +Prototype: GG +Help: quadunitindex(D,f): given a fundamental discriminant D, returns the + index of the unit group of the order of conductor f. +Doc: given a fundamental discriminant $D$, returns the index of the unit group + of the order of conductor $f$ in the units of $\Q(\sqrt{D})$. This function + uses the continued fraction algorithm and has $O(D^{1/2 + \varepsilon} + f^{\varepsilon})$ complexity; \kbd{quadclassunit} is asymptotically faster but + depends on the GRH. + \bprog + ? quadunitindex(-3, 2) + %1 = 3 + ? quadunitindex(5, 2^32) \\ instantaneous + %2 = 3221225472 + ? quadregulator(5 * 2^64) / quadregulator(5) + time = 3min, 1,488 ms. + %3 = 3221225472.0000000000000000000000000000 + @eprog\noindent The conductor $f$ can be given in factored form or as + $[f, \kbd{factor}(f)]$: + \bprog + ? quadunitindex(5, [100, [2,2;5,2]]) + %4 = 150 + ? quadunitindex(5, 100) + %5 = 150 + ? quadunitindex(5, [2,2;5,2]) + %6 = 150 + @eprog + If $D$ is not fundamental, the result is undefined; you may use the + following script instead: + \bprog + index(d, f) = + { my([D,F] = coredisc(d, 1)); + quadunitindex(D, f * F) / quadunitindex(D, F) + } + ? index(5 * 10^2, 10) + %7 = 10 + @eprog + +Function: quadunitnorm +Class: basic +Section: number_theoretical +C-Name: quadunitnorm +Prototype: lG +Help: quadunitnorm(D): returns the norm of the fundamental unit of the + quadratic order of discriminant D. +Doc: returns the norm ($1$ or $-1$) of the fundamental unit of the quadratic + order of discriminant $D$. The integer $D$ must be congruent to $0$ or $1$ + modulo $4$ and not a square. This is of course equal to \kbd{norm(quadunit(D))} + but faster. + \bprog + ? quadunitnorm(-3) \\ the result is always 1 in the imaginary case + %1 = 1 + ? quadunitnorm(5) + %2 = -1 + ? quadunitnorm(17345) + %3 = -1 + ? u = quadunit(17345) + %4 = 299685042291 + 4585831442*w + ? norm(u) + %5 = -1 + @eprog\noindent This function computes the parity of the continued fraction + expansion and runs in time $\tilde{O}(D^{1/2})$. If $D$ is fundamental, + the function \kbd{bnfinit} is asymptotically faster but depends of the GRH. + If $D = df^{2}$ is not fundamental, it will usually be faster to first compute + \kbd{quadunitindex}$(d, f)$. If it is even, the result is $1$, else the result + is \kbd{quadunitnorm}$(d)$. The narrow class number of the order of + discriminant $D$ is equal to the class number if the unit norm is $1$ and to + twice the class number otherwise. + + \misctitle{Important remark} Assuming GRH, using \kbd{bnfinit} is \emph{much} + faster, running in time subexponential in $\log D$ (instead of exponential + for \kbd{quadunitnorm}). We give examples for the maximal order: + \bprog + ? GRHunitnorm(bnf) = vecprod(bnfsignunit(bnf)[,1]) + ? bnf = bnfinit(x^2 - 17345, 1); GRHunitnorm(bnf) + %2 = -1 + ? bnf = bnfinit(x^2 - nextprime(2^60), 1); GRHunitnorm(bnf) + time = 119 ms. + %3 = -1 + ? quadunitnorm(nextprime(2^60)) + time = 24,086 ms. + %4 = -1 + @eprog\noindent Note that if the result is $-1$, it is unconditional because + (if GRH is false) it could happen that our tentative fundamental unit in + \var{bnf} is actually a power $u^{k}$ of the true fundamental unit, but we + would still have $\text{Norm}(u) = -1$ (and $k$ odd). We can also remove the + GRH assumption when the result is $1$ with a little more work: + \bprog + ? v = bnfunits(bnf)[1][1] \\ a unit in factored form + ? v[,2] %= 2; + ? nfeltissquare(bnf, nffactorback(bnf, v)) + %7 = 0 + @eprog\noindent Under GRH, we know that $v$ is the fundamental unit, but as + above it can be a power $u^{k}$ of the true fundamental unit $u$. But the + final two lines prove that $v$ is not a square, hence $k$ is odd and + $\text{Norm}(u)$ must also be $1$. We modified the factorization matrix + giving $v$ by reducing all exponents modulo $2$: this allows to computed + \kbd{nffactorback} even when the factorization involves huge exponents. + And of course the new $v$ is a square if and only if the original one was. + +Function: quit +Class: gp +Section: programming/specific +C-Name: gp_quit +Prototype: vD0,L, +Help: quit({status = 0}): quit, return to the system with exit status + 'status'. +Doc: exits \kbd{gp} and return to the system with exit status + \kbd{status}, a small integer. A nonzero exit status normally indicates + abnormal termination. (Note: the system actually sees only + \kbd{status} mod $256$, see your man pages for \kbd{exit(3)} or \kbd{wait(2)}). + +Function: ramanujantau +Class: basic +Section: number_theoretical +C-Name: ramanujantau +Prototype: GD12,L, +Help: ramanujantau(n,{ell=12}): compute the value of Ramanujan's tau function + at n, assuming the GRH. If ell is 16, 18, 20, 22, or 26, same for the + newform of level 1 and corresponding weight. Otherwise, compute the + coefficient of the trace form at n. Algorithm in O(n^{1/2+eps}). +Doc: compute the value of Ramanujan's tau function at an individual $n$, + assuming the truth of the GRH (to compute quickly class numbers of imaginary + quadratic fields using \tet{quadclassunit}). If \kbd{ell} is 16, 18, 20, 22, + or 26, same for the newform of level 1 and corresponding weight. Otherwise, + compute the coefficient of the trace form at $n$. + The complexity is in $\tilde{O}(n^{1/2})$ using $O(\log n)$ space. + + If all values up to $N$ are required, then + $$\sum \tau(n)q^{n} = q \prod_{n\geq 1} (1-q^{n})^{24}$$ + and more generally, setting $u = \ell - 13$ and $C = 2/\zeta(-u)$ for $\ell + > 12$, + $$\sum\tau_{\ell}(n)q^{n} = q \prod_{n\geq 1} + (1-q^{n})^{24} \Big( 1 + C\sum_{n\ge1}n^{u} q^{n} / (1-q^{n})\Big)$$ + produces them in time $\tilde{O}(N)$, against $\tilde{O}(N^{3/2})$ for + individual calls to \kbd{ramanujantau}; of course the space complexity then + becomes $\tilde{O}(N)$. For other values of $\ell$, + \kbd{mfcoefs(mftraceform([1,ell]),N)} is much faster. + \bprog + ? tauvec(N) = Vec(q*eta(q + O(q^N))^24); + ? N = 10^4; v = tauvec(N); + time = 26 ms. + ? ramanujantau(N) + %3 = -482606811957501440000 + ? w = vector(N, n, ramanujantau(n)); \\ much slower ! + time = 13,190 ms. + ? v == w + %4 = 1 + @eprog + +Function: random +Class: basic +Section: conversions +C-Name: genrand +Prototype: DG +Help: random({N=2^31}): random object, depending on the type of N. + Integer between 0 and N-1 (t_INT), int mod N (t_INTMOD), element in a finite + field (t_FFELT), point on an elliptic curve (ellinit mod p or over a finite + field). +Description: + (?int):int genrand($1) + (real):real genrand($1) + (gen):gen genrand($1) +Doc: + returns a random element in various natural sets depending on the + argument $N$. + + \item \typ{INT}: let $n = |N|-1$; if $N > 0$ returns an integer uniformly + distributed in $[0, n]$; if $N < 0$ returns an integer uniformly + distributed in $[-n, n]$. Omitting the argument is + equivalent to \kbd{random(2\pow31)}. + + \item \typ{REAL}: returns a real number in $[0,1[$ with the same accuracy as + $N$ (whose mantissa has the same number of significant words). + + \item \typ{INTMOD}: returns a random intmod for the same modulus. + + \item \typ{FFELT}: returns a random element in the same finite field. + + \item \typ{VEC} of length $2$, $N = [a,b]$: returns an integer uniformly + distributed between $a$ and $b$. + + \item \typ{VEC} generated by \kbd{ellinit} over a finite field $k$ + (coefficients are \typ{INTMOD}s modulo a prime or \typ{FFELT}s): returns a + ``random'' $k$-rational \emph{affine} point on the curve. More precisely + if the curve has a single point (at infinity!) we return it; otherwise + we return an affine point by drawing an abscissa uniformly at + random until \tet{ellordinate} succeeds. Note that this is definitely not a + uniform distribution over $E(k)$, but it should be good enough for + applications. + + \item \typ{POL} return a random polynomial of degree at most the degree of $N$. + The coefficients are drawn by applying \kbd{random} to the leading + coefficient of $N$. + + \bprog + ? random(10) + %1 = 9 + ? random(Mod(0,7)) + %2 = Mod(1, 7) + ? a = ffgen(ffinit(3,7), 'a); random(a) + %3 = a^6 + 2*a^5 + a^4 + a^3 + a^2 + 2*a + ? E = ellinit([3,7]*Mod(1,109)); random(E) + %4 = [Mod(103, 109), Mod(10, 109)] + ? E = ellinit([1,7]*a^0); random(E) + %5 = [a^6 + a^5 + 2*a^4 + 2*a^2, 2*a^6 + 2*a^4 + 2*a^3 + a^2 + 2*a] + ? random(Mod(1,7)*x^4) + %6 = Mod(5, 7)*x^4 + Mod(6, 7)*x^3 + Mod(2, 7)*x^2 + Mod(2, 7)*x + Mod(5, 7) + + @eprog + These variants all depend on a single internal generator, and are + independent from your operating system's random number generators. + A random seed may be obtained via \tet{getrand}, and reset + using \tet{setrand}: from a given seed, and given sequence of \kbd{random}s, + the exact same values will be generated. The same seed is used at each + startup, reseed the generator yourself if this is a problem. Note that + internal functions also call the random number generator; adding such a + function call in the middle of your code will change the numbers produced. + + \misctitle{Technical note} + Up to + version 2.4 included, the internal generator produced pseudo-random numbers + by means of linear congruences, which were not well distributed in arithmetic + progressions. We now + use Brent's XORGEN algorithm, based on Feedback Shift Registers, see + \url{https://wwwmaths.anu.edu.au/~brent/random.html}. The generator has period + $2^{4096}-1$, passes the Crush battery of statistical tests of L'Ecuyer and + Simard, but is not suitable for cryptographic purposes: one can reconstruct + the state vector from a small sample of consecutive values, thus predicting + the entire sequence. + + \misctitle{Parallelism} In multi-threaded programs, each thread has a + separate generator. They all start in the same \kbd{setrand(1)} state, so + will all produce the same sequence of pseudo-random numbers although + the various states are not shared. To avoid this, use \kbd{setrand} to + provide a different starting state to each thread: + \bprog + \\ with 8 threads + ? parvector(8, i, random()) \\ all 8 threads return the same number + %1 = [1546275796, 1546275796, ... , 1546275796] + ? parvector(8, i, random()) \\ ... and again since they are restarted + %2 = [1546275796, 1546275796, ... , 1546275796] + + ? s = [1..8]; \\ 8 random seeds; we could use vector(8,i,random()) + ? parvector(8, i, setrand(s[i]); random()) + \\ now we get 8 different numbers + @eprog +Variant: + Also available: \fun{GEN}{ellrandom}{GEN E} and \fun{GEN}{ffrandom}{GEN a}. + +Function: randomprime +Class: basic +Section: number_theoretical +C-Name: randomprime0 +Prototype: DGDG +Help: randomprime({N=2^31},{q}): returns a strong pseudo prime in [2, N-1]. + If q is an integer, return a prime = 1 mod q; if q is an intmod, return + a prime in the given congruence class. +Doc: returns a strong pseudo prime (see \tet{ispseudoprime}) in $[2,N-1]$. + A \typ{VEC} $N = [a,b]$ is also allowed, with $a \leq b$ in which case a + pseudo prime $a \leq p \leq b$ is returned; if no prime exists in the + interval, the function will run into an infinite loop. If the upper bound + is less than $2^{64}$ the pseudo prime returned is a proven prime. + + \bprog + ? randomprime(100) + %1 = 71 + ? randomprime([3,100]) + %2 = 61 + ? randomprime([1,1]) + *** at top-level: randomprime([1,1]) + *** ^------------------ + *** randomprime: domain error in randomprime: + *** floor(b) - max(ceil(a),2) < 0 + ? randomprime([24,28]) \\ infinite loop + @eprog + + If the optional parameter $q$ is an integer, return a prime congruent to $1 + \mod q$; if $q$ is an intmod, return a prime in the given congruence class. + If the class contains no prime in the given interval, the function will raise + an exception if the class is not invertible, else run into an infinite loop + + \bprog + ? randomprime(100, 4) \\ 1 mod 4 + %1 = 71 + ? randomprime(100, 4) + %2 = 13 + ? randomprime([10,100], Mod(2,5)) + %3 = 47 + ? randomprime(100, Mod(0,2)) \\ silly but works + %4 = 2 + ? randomprime([3,100], Mod(0,2)) \\ not invertible + *** at top-level: randomprime([3,100],Mod(0,2)) + *** ^----------------------------- + *** randomprime: elements not coprime in randomprime: + 0 + 2 + ? randomprime(100, 97) \\ infinite loop + @eprog +Variant: Also available is \fun{GEN}{randomprime}{GEN N = NULL}. + +Function: read +Class: basic +Section: programming/specific +C-Name: gp_read_file +Prototype: D"",s, +Help: read({filename}): read from the input file filename. If filename is + omitted, reread last input file, be it from read() or \r. +Description: + (str):gen gp_read_file($1) +Doc: reads in the file + \var{filename} (subject to string expansion). If \var{filename} is + omitted, re-reads the last file that was fed into \kbd{gp}. The return + value is the result of the last expression evaluated. + + If a GP \tet{binary file} is read using this command (see + \secref{se:writebin}), the file is loaded and the last object in the file + is returned. + + In case the file you read in contains an \tet{allocatemem} statement (to be + generally avoided), you should leave \kbd{read} instructions by themselves, + and not part of larger instruction sequences. + + \misctitle{Variants} \kbd{readvec} allows to read a whole file at once; + \kbd{fileopen} followed by either \kbd{fileread} (evaluated lines) or + \kbd{filereadstr} (lines as nonevaluated strings) allows to read a file + one line at a time. + +Function: readstr +Class: basic +Section: programming/specific +C-Name: readstr +Prototype: D"",s, +Help: readstr({filename}): returns the vector of GP strings containing + the lines in filename. +Doc: Reads in the file \var{filename} and return a vector of GP strings, + each component containing one line from the file. If \var{filename} is + omitted, re-reads the last file that was fed into \kbd{gp}. + +Function: readvec +Class: basic +Section: programming/specific +C-Name: gp_readvec_file +Prototype: D"",s, +Help: readvec({filename}): create a vector whose components are the evaluation + of all the expressions found in the input file filename. +Description: + (str):gen gp_readvec_file($1) +Doc: reads in the file + \var{filename} (subject to string expansion). If \var{filename} is + omitted, re-reads the last file that was fed into \kbd{gp}. The return + value is a vector whose components are the evaluation of all sequences + of instructions contained in the file. For instance, if \var{file} contains + \bprog + 1 + 2 + 3 + @eprog\noindent + then we will get: + \bprog + ? \r a + %1 = 1 + %2 = 2 + %3 = 3 + ? read(a) + %4 = 3 + ? readvec(a) + %5 = [1, 2, 3] + @eprog + In general a sequence is just a single line, but as usual braces and + \kbd{\bs} may be used to enter multiline sequences. +Variant: The underlying library function + \fun{GEN}{gp_readvec_stream}{FILE *f} is usually more flexible. + +Function: real +Class: basic +Section: conversions +C-Name: greal +Prototype: G +Help: real(x): real part of x. +Doc: real part of $x$. When $x$ is a quadratic number, this is the + coefficient of $1$ in the ``canonical'' integral basis $(1,\omega)$. + \bprog + ? real(3 + I) + %1 = 3 + ? x = 3 + quadgen(-23); + ? real(x) \\ as a quadratic number + %3 = 3 + ? real(x * 1.) \\ as a complex number + %4 = 3.5000000000000000000000000000000000000 + @eprog + +Function: removeprimes +Class: basic +Section: number_theoretical +C-Name: removeprimes +Prototype: DG +Help: removeprimes({x=[]}): remove primes in the vector x from the prime table. + x can also be a single integer. List the current extra primes if x is omitted. +Doc: removes the primes listed in $x$ from + the prime number table. In particular \kbd{removeprimes(addprimes())} empties + the extra prime table. $x$ can also be a single integer. List the current + extra primes if $x$ is omitted. + +Function: return +Class: basic +Section: programming/control +C-Name: return0 +Prototype: DG +Help: return({x=0}): return from current subroutine with result x. +Doc: returns from current subroutine, with + result $x$. If $x$ is omitted, return the \kbd{(void)} value (return no + result, like \kbd{print}). + +Function: rnfalgtobasis +Class: basic +Section: number_fields +C-Name: rnfalgtobasis +Prototype: GG +Help: rnfalgtobasis(rnf,x): relative version of nfalgtobasis, where rnf is a + relative numberfield. +Doc: expresses $x$ on the relative + integral basis. Here, $\var{rnf}$ is a relative number field extension $L/K$ + as output by \kbd{rnfinit}, and $x$ an element of $L$ in absolute form, i.e. + expressed as a polynomial or polmod with polmod coefficients, \emph{not} on + the relative integral basis. + +Function: rnfbasis +Class: basic +Section: number_fields +C-Name: rnfbasis +Prototype: GG +Help: rnfbasis(bnf,M): given a projective Z_K-module M as output by + rnfpseudobasis or rnfsteinitz, gives either a basis of M if it is free, or an + n+1-element generating set. +Doc: let $K$ the field represented by + \var{bnf}, as output by \kbd{bnfinit}. $M$ is a projective $\Z_{K}$-module + of rank $n$ ($M\otimes K$ is an $n$-dimensional $K$-vector space), given by a + pseudo-basis of size $n$. The routine returns either a true $\Z_{K}$-basis of + $M$ (of size $n$) if it exists, or an $n+1$-element generating set of $M$ if + not. + + It is allowed to use a monic irreducible polynomial $P$ in $K[X]$ instead of + $M$, in which case, $M$ is defined as the ring of integers of $K[X]/(P)$, + viewed as a $\Z_{K}$-module. + + \misctitle{Huge discriminants, helping rnfdisc} The format $[T,B]$ is + also accepted instead of $T$ and computes an order which is maximal at all + maximal ideals specified by $B$, see \kbd{??rnfinit}: the valuation of $D$ is + then correct at all such maximal ideals but may be incorrect at other primes. + +Function: rnfbasistoalg +Class: basic +Section: number_fields +C-Name: rnfbasistoalg +Prototype: GG +Help: rnfbasistoalg(rnf,x): relative version of nfbasistoalg, where rnf is a + relative numberfield. +Doc: computes the representation of $x$ + as a polmod with polmods coefficients. Here, $\var{rnf}$ is a relative number + field extension $L/K$ as output by \kbd{rnfinit}, and $x$ an element of + $L$ expressed on the relative integral basis. + +Function: rnfcharpoly +Class: basic +Section: number_fields +C-Name: rnfcharpoly +Prototype: GGGDn +Help: rnfcharpoly(nf,T,a,{var='x}): characteristic polynomial of a + over nf, where a belongs to the algebra defined by T over nf. Returns a + polynomial in variable var (x by default). +Doc: characteristic polynomial of + $a$ over $\var{nf}$, where $a$ belongs to the algebra defined by $T$ over + $\var{nf}$, i.e.~$\var{nf}[X]/(T)$. Returns a polynomial in variable $v$ + ($x$ by default). + \bprog + ? nf = nfinit(y^2+1); + ? rnfcharpoly(nf, x^2+y*x+1, x+y) + %2 = x^2 + Mod(-y, y^2 + 1)*x + 1 + @eprog + +Function: rnfconductor +Class: basic +Section: number_fields +C-Name: rnfconductor0 +Prototype: GGD0,L, +Help: rnfconductor(bnf,T,{flag=0}): conductor of the Abelian extension + of bnf defined by T. The result is [conductor,bnr,subgroup], + where conductor is the conductor itself, bnr the attached bnr + structure, and subgroup the HNF defining the norm + group (Artin or Takagi group) on the given generators bnr.gen. + If flag is 1, return a bnr modulo deg(T), attached to Cl_f / (deg(T)); + if flag is 2 only return [f, idealfactor(f[1])]. +Doc: given a \var{bnf} structure attached to a number field $K$, as produced + by \kbd{bnfinit}, and $T$ an irreducible polynomial in $K[x]$ + defining an \idx{Abelian extension} $L = K[x]/(T)$, computes the class field + theory conductor of this Abelian extension. If $T$ does not define an Abelian + extension over $K$, the result is undefined; it may be the integer $0$ (in + which case the extension is definitely not Abelian) or a wrong result. + + The result is a 3-component vector $[f,\var{bnr},H]$, where $f$ is the + conductor of the extension given as a 2-component row vector + $[f_{0},f_{\infty}]$, + \var{bnr} is the attached \kbd{bnr} structure and $H$ is a matrix in HNF + defining the subgroup of the ray class group on the ray class group generators + \kbd{bnr.gen}; in particular, it is a left divisor of the diagonal matrix + attached to \kbd{bnr.cyc} and $|\det H| = N = \deg T$. + + \item If \fl\ is $1$, return $[f,\var{bnrmod}, H]$, where + \kbd{bnrmod} is now attached to $\text{Cl}_{f} / \text{Cl}_{f}^{N}$, + and $H$ is as + before since it contains the $N$-th powers. This is useful when $f$ contains + a maximal ideal with huge residue field, since the corresponding tough + discrete logarithms are trivialized: in the quotient group, all elements have + small order dividing $N$. This allows to work in $\text{Cl}_{f}/H$ but no + longer in $\text{Cl}_{f}$. + + \item If \fl\ is $2$, only return $[f, \kbd{fa}]$ where \kbd{fa} is the + factorization of the conductor finite part ($=f[1]$). + + \misctitle{Huge discriminants, helping rnfdisc} The format $[T,B]$ is + also accepted instead of $T$ and computes the conductor of the extension + provided it factors completely over the maximal ideals specified by $B$, + see \kbd{??rnfinit}: the valuation of $f_{0}$ is then correct at all such + maximal ideals but may be incorrect at other primes. +Variant: Also available is \fun{GEN}{rnfconductor}{GEN bnf, GEN T} when $\fl = + 0$. + +Function: rnfdedekind +Class: basic +Section: number_fields +C-Name: rnfdedekind +Prototype: GGDGD0,L, +Help: rnfdedekind(nf,pol,{pr},{flag=0}): relative Dedekind criterion over the + number field K, represented by nf, applied to the order Z_K[X]/(P), + modulo the prime ideal pr (at all primes if pr omitted, in which case + flag is automatically set to 1). + P is assumed to be monic, irreducible, in Z_K[X]. + Returns [max,basis,v], where basis is a pseudo-basis of the + enlarged order, max is 1 iff this order is pr-maximal, and v is the + valuation at pr of the order discriminant. If flag is set, just return 1 if + the order is maximal, and 0 if not. +Doc: given a number field $K$ coded by $\var{nf}$ and a monic + polynomial $P\in \Z_{K}[X]$, irreducible over $K$ and thus defining a relative + extension $L$ of $K$, applies \idx{Dedekind}'s criterion to the order + $\Z_{K}[X]/(P)$, at the prime ideal \var{pr}. It is possible to set \var{pr} + to a vector of prime ideals (test maximality at all primes in the vector), + or to omit altogether, in which case maximality at \emph{all} primes is tested; + in this situation \fl\ is automatically set to $1$. + + The default historic behavior (\fl\ is 0 or omitted and \var{pr} is a + single prime ideal) is not so useful since + \kbd{rnfpseudobasis} gives more information and is generally not that + much slower. It returns a 3-component vector $[\var{max}, \var{basis}, v]$: + + \item \var{basis} is a pseudo-basis of an enlarged order $O$ produced by + Dedekind's criterion, containing the original order $\Z_{K}[X]/(P)$ + with index a power of \var{pr}. Possibly equal to the original order. + + \item \var{max} is a flag equal to 1 if the enlarged order $O$ + could be proven to be \var{pr}-maximal and to 0 otherwise; it may still be + maximal in the latter case if \var{pr} is ramified in $L$, + + \item $v$ is the valuation at \var{pr} of the order discriminant. + + If \fl\ is nonzero, on the other hand, we just return $1$ if the order + $\Z_{K}[X]/(P)$ is \var{pr}-maximal (resp.~maximal at all relevant primes, as + described above), and $0$ if not. This is much faster than the default, + since the enlarged order is not computed. + \bprog + ? nf = nfinit(y^2-3); P = x^3 - 2*y; + ? pr3 = idealprimedec(nf,3)[1]; + ? rnfdedekind(nf, P, pr3) + %3 = [1, [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, 1]], 8] + ? rnfdedekind(nf, P, pr3, 1) + %4 = 1 + @eprog\noindent In this example, \kbd{pr3} is the ramified ideal above $3$, + and the order generated by the cube roots of $y$ is already + \kbd{pr3}-maximal. The order-discriminant has valuation $8$. On the other + hand, the order is not maximal at the prime above 2: + \bprog + ? pr2 = idealprimedec(nf,2)[1]; + ? rnfdedekind(nf, P, pr2, 1) + %6 = 0 + ? rnfdedekind(nf, P, pr2) + %7 = [0, [[2, 0, 0; 0, 1, 0; 0, 0, 1], [[1, 0; 0, 1], [1, 0; 0, 1], + [1, 1/2; 0, 1/2]]], 2] + @eprog + The enlarged order is not proven to be \kbd{pr2}-maximal yet. In fact, it + is; it is in fact the maximal order: + \bprog + ? B = rnfpseudobasis(nf, P) + %8 = [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, [1, 1/2; 0, 1/2]], + [162, 0; 0, 162], -1] + ? idealval(nf,B[3], pr2) + %9 = 2 + @eprog\noindent + It is possible to use this routine with nonmonic + $P = \sum_{i\leq n} p_{i} X^{i} \in \Z_{K}[X]$ if $\fl = 1$; + in this case, we test maximality of Dedekind's order generated by + $$1, p_{n} \alpha, p_{n}\alpha^{2} + p_{n-1}\alpha, \dots, + p_{n}\alpha^{n-1} + p_{n-1}\alpha^{n-2} + \cdots + p_{1}\alpha.$$ + The routine will fail if $P$ vanishes on the projective line over the residue + field $\Z_{K}/\kbd{pr}$ (FIXME). + +Function: rnfdet +Class: basic +Section: number_fields +C-Name: rnfdet +Prototype: GG +Help: rnfdet(nf,M): given a pseudo-matrix M, compute its determinant. +Doc: given a pseudo-matrix $M$ over the maximal + order of $\var{nf}$, computes its determinant. + +Function: rnfdisc +Class: basic +Section: number_fields +C-Name: rnfdiscf +Prototype: GG +Help: rnfdisc(nf,T): given a polynomial T with coefficients in nf, gives a + 2-component vector [D,d], where D is the relative ideal discriminant, and d + is the relative discriminant in nf^*/nf*^2. +Doc: given an \var{nf} structure attached to a number field $K$, as output + by \kbd{nfinit}, and a monic irreducible polynomial $T\in K[x]$ defining a + relative extension $L = K[x]/(T)$, compute the relative discriminant of $L$. + This is a vector $[D,d]$, where $D$ is the relative ideal discriminant and + $d$ is the relative discriminant considered as an element of + $K^{*}/{K^{*}}^{2}$. + The main variable of $\var{nf}$ \emph{must} be of lower priority than that of + $T$, see \secref{se:priority}. + + \misctitle{Huge discriminants, helping rnfdisc} The format $[T,B]$ is + also accepted instead of $T$ and computes an order which is maximal at all + maximal ideals specified by $B$, see \kbd{??rnfinit}: the valuation of $D$ is + then correct at all such maximal ideals but may be incorrect at other primes. + +Function: rnfeltabstorel +Class: basic +Section: number_fields +C-Name: rnfeltabstorel +Prototype: GG +Help: rnfeltabstorel(rnf,x): transforms the element x from absolute to + relative representation. +Doc: Let $\var{rnf}$ be a relative number field extension $L/K$ as output by + \kbd{rnfinit} and let $x$ be an + element of $L$ expressed either + + \item as a polynomial modulo the absolute equation \kbd{\var{rnf}.polabs}, + + \item or in terms of the absolute $\Z$-basis for $\Z_{L}$ if \var{rnf} + contains one (as in \kbd{rnfinit(nf,pol,1)}, or after a call to + \kbd{nfinit(rnf)}). + + Computes $x$ as an element of the relative extension $L/K$ as a polmod with + polmod coefficients. If $x$ is actually rational, return it as a rational + number: + \bprog + ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); + ? L.polabs + %2 = x^4 + 1 + ? rnfeltabstorel(L, Mod(x, L.polabs)) + %3 = Mod(x, x^2 + Mod(-y, y^2 + 1)) + ? rnfeltabstorel(L, 1/3) + %4 = 1/3 + ? rnfeltabstorel(L, Mod(x, x^2-y)) + %5 = Mod(x, x^2 + Mod(-y, y^2 + 1)) + + ? rnfeltabstorel(L, [0,0,0,1]~) \\ Z_L not initialized yet + *** at top-level: rnfeltabstorel(L,[0, + *** ^-------------------- + *** rnfeltabstorel: incorrect type in rnfeltabstorel, apply nfinit(rnf). + ? nfinit(L); \\ initialize now + ? rnfeltabstorel(L, [0,0,0,1]~) + %6 = Mod(Mod(y, y^2 + 1)*x, x^2 + Mod(-y, y^2 + 1)) + ? rnfeltabstorel(L, [1,0,0,0]~) + %7 = 1 + @eprog + +Function: rnfeltdown +Class: basic +Section: number_fields +C-Name: rnfeltdown0 +Prototype: GGD0,L, +Help: rnfeltdown(rnf,x,{flag=0}): expresses x on the base field if possible; + returns an error otherwise. +Doc: $\var{rnf}$ being a relative number + field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an element of + $L$ expressed as a polynomial or polmod with polmod coefficients (or as a + \typ{COL} on \kbd{nfinit(rnf).zk}), computes + $x$ as an element of $K$ as a \typ{POLMOD} if $\fl = 0$ and as a \typ{COL} + otherwise. If $x$ is not in $K$, a domain error occurs. Note that if $x$ + is in fact rational, it is returned as a rational number, ignoring \fl. + \bprog + ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); + ? L.pol + %2 = x^4 + 1 + ? rnfeltdown(L, Mod(x^2, L.pol)) + %3 = Mod(y, y^2 + 1) + ? rnfeltdown(L, Mod(x^2, L.pol), 1) + %4 = [0, 1]~ + ? rnfeltdown(L, Mod(y, x^2-y)) + %5 = Mod(y, y^2 + 1) + ? rnfeltdown(L, Mod(y,K.pol)) + %6 = Mod(y, y^2 + 1) + ? rnfeltdown(L, Mod(x, L.pol)) + *** at top-level: rnfeltdown(L,Mod(x,x + *** ^-------------------- + *** rnfeltdown: domain error in rnfeltdown: element not in the base field + ? rnfeltdown(L, Mod(y, x^2-y), 1) \\ as a t_COL + %7 = [0, 1]~ + ? rnfeltdown(L, [0,0,1,0]~) \\ not allowed without absolute nf struct + *** rnfeltdown: incorrect type in rnfeltdown (t_COL). + ? nfinit(L); \\ add absolute nf structure to L + ? rnfeltdown(L, [0,0,1,0]~) \\ now OK + %8 = Mod(y, y^2 + 1) + @eprog\noindent If we had started with + \kbd{L = rnfinit(K, x\pow2-y, 1)}, then the final command would have worked + directly. +Variant: Also available is + \fun{GEN}{rnfeltdown}{GEN rnf, GEN x} ($\fl = 0$). + +Function: rnfeltnorm +Class: basic +Section: number_fields +C-Name: rnfeltnorm +Prototype: GG +Help: rnfeltnorm(rnf,x): returns the relative norm N_{L/K}(x), as an element + of K. +Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by + \kbd{rnfinit} and $x$ being an element of $L$, returns the relative norm + $N_{L/K}(x)$ as an element of $K$. + \bprog + ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); + ? rnfeltnorm(L, Mod(x, L.pol)) + %2 = Mod(x, x^2 + Mod(-y, y^2 + 1)) + ? rnfeltnorm(L, 2) + %3 = 4 + @eprog + +Function: rnfeltreltoabs +Class: basic +Section: number_fields +C-Name: rnfeltreltoabs +Prototype: GG +Help: rnfeltreltoabs(rnf,x): transforms the element x from relative to + absolute representation. +Doc: $\var{rnf}$ being a relative + number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an + element of $L$ expressed as a polynomial or polmod with polmod + coefficients, computes $x$ as an element of the absolute extension $L/\Q$ as + a polynomial modulo the absolute equation \kbd{\var{rnf}.polabs}. + \bprog + ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); + ? L.polabs + %2 = x^4 + 1 + ? rnfeltreltoabs(L, Mod(x, L.pol)) + %3 = Mod(x, x^4 + 1) + ? rnfeltreltoabs(L, Mod(y, x^2-y)) + %4 = Mod(x^2, x^4 + 1) + ? rnfeltreltoabs(L, Mod(y,K.pol)) + %5 = Mod(x^2, x^4 + 1) + @eprog\noindent If the input is actually rational, then \kbd{rnfeltreltoabs} + returns it as a rational number instead of a \typ{POLMOD}: + \bprog + ? rnfeltreltoabs(L, Mod(2, K.pol)) + %6 = 2 + @eprog + +Function: rnfelttrace +Class: basic +Section: number_fields +C-Name: rnfelttrace +Prototype: GG +Help: rnfelttrace(rnf,x): returns the relative trace Tr_{L/K}(x), as an element + of K. +Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by + \kbd{rnfinit} and $x$ being an element of $L$, returns the relative trace + $Tr_{L/K}(x)$ as an element of $K$. + \bprog + ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); + ? rnfelttrace(L, Mod(x, L.pol)) + %2 = 0 + ? rnfelttrace(L, 2) + %3 = 4 + @eprog + +Function: rnfeltup +Class: basic +Section: number_fields +C-Name: rnfeltup0 +Prototype: GGD0,L, +Help: rnfeltup(rnf,x,{flag=0}): expresses x (belonging to the base field) on + the relative field. As a t_POLMOD if flag = 0 and as a t_COL on the absolute + field integer basis if flag = 1. +Doc: $\var{rnf}$ being a relative number field extension $L/K$ as output by + \kbd{rnfinit} and $x$ being an element of $K$, computes $x$ as an element of + the absolute extension $L/\Q$. As a \typ{POLMOD} modulo \kbd{\var{rnf}.pol} + if $\fl = 0$ and as a \typ{COL} on the absolute field integer basis if + $\fl = 1$. Note that if $x$ + is in fact rational, it is returned as a rational number, ignoring \fl. + \bprog + ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); + ? L.pol + %2 = x^4 + 1 + ? rnfeltup(L, Mod(y, K.pol)) + %3 = Mod(x^2, x^4 + 1) + ? rnfeltup(L, y) + %4 = Mod(x^2, x^4 + 1) + ? rnfeltup(L, [1,2]~) \\ in terms of K.zk + %5 = Mod(2*x^2 + 1, x^4 + 1) + ? rnfeltup(L, y, 1) \\ in terms of nfinit(L).zk + %6 = [0, 1, 0, 0]~ + ? rnfeltup(L, [1,2]~, 1) + %7 = [1, 2, 0, 0]~ + ? rnfeltup(L, [1,0]~) \\ rational + %8 = 1 + @eprog +Variant: Also available is + \fun{GEN}{rnfeltup}{GEN rnf, GEN x} ($\fl = 0$). + +Function: rnfequation +Class: basic +Section: number_fields +C-Name: rnfequation0 +Prototype: GGD0,L, +Help: rnfequation(nf,pol,{flag=0}): given a pol with coefficients in nf, + gives an absolute equation z of the number field defined by pol. flag is + optional, and can be 0: default, or nonzero, gives [z,al,k], where + z defines the absolute equation L/Q as in the default behavior, + al expresses as an element of L a root of the polynomial + defining the base field nf, and k is a small integer such that + t = b + k al is a root of z, for b a root of pol. +Doc: given a number field $\var{nf}$ as output by \kbd{nfinit} + (or simply a monic irreducible integral polynomial defining the field) + and a polynomial \var{pol} with coefficients in $\var{nf}$ defining a + relative extension $L$ of $\var{nf}$, computes an absolute equation of $L$ + over $\Q$. + + The main variable of $\var{nf}$ \emph{must} be of lower priority than that + of \var{pol} (see \secref{se:priority}). Note that for efficiency, this does + not check whether the relative equation is irreducible over $\var{nf}$, but + only if it is squarefree. If it is reducible but squarefree, the result will + be the absolute equation of the \'etale algebra defined by \var{pol}. If + \var{pol} is not squarefree, raise an \kbd{e\_DOMAIN} exception. + \bprog + ? rnfequation(y^2+1, x^2 - y) + %1 = x^4 + 1 + ? T = y^3-2; rnfequation(nfinit(T), (x^3-2)/(x-Mod(y,T))) + %2 = x^6 + 108 \\ Galois closure of Q(2^(1/3)) + @eprog + + If $\fl$ is nonzero, outputs a 3-component row vector $[z,a,k]$, where + + \item $z$ is the absolute equation of $L$ over $\Q$, as in the default + behavior, + + \item $a$ expresses as a \typ{POLMOD} modulo $z$ a root $\alpha$ of the + polynomial defining the base field $\var{nf}$, + + \item $k$ is a small integer such that $\theta = \beta+k\alpha$ + is a root of $z$, where $\beta$ is a root of $\var{pol}$. It is guaranteed + that $k=0$ whenever $\Q(\beta) = L$. + \bprog + ? T = y^3-2; pol = x^2 +x*y + y^2; + ? [z,a,k] = rnfequation(T, pol, 1); + ? z + %3 = x^6 + 108 + ? subst(T, y, a) + %4 = 0 + ? alpha= Mod(y, T); + ? beta = Mod(x*Mod(1,T), pol); + ? subst(z, x, beta + k*alpha) + %7 = 0 + @eprog +Variant: Also available are + \fun{GEN}{rnfequation}{GEN nf, GEN pol} ($\fl = 0$) and + \fun{GEN}{rnfequation2}{GEN nf, GEN pol} ($\fl = 1$). + +Function: rnfhnfbasis +Class: basic +Section: number_fields +C-Name: rnfhnfbasis +Prototype: GG +Help: rnfhnfbasis(bnf,M): given a bnf attached to a number field K and a + projective Z_K module M given by a pseudo-matrix, returns either a true + HNF basis of M if one exists, or zero otherwise. If M is a polynomial with + coefficients in K, replace it by the pseudo-matrix returned by + rnfpseudobasis. +Doc: given a \var{bnf} attached to a number field $K$ and a projective + $\Z_{K}$-module $M$ given by a pseudo-matrix, returns either a true HNF basis + of $M$ if one exists, or zero otherwise. If $M$ is a polynomial with + coefficients in $K$, replace it by the pseudo-matrix returned by + \kbd{rnfpseudobasis}. + +Function: rnfidealabstorel +Class: basic +Section: number_fields +C-Name: rnfidealabstorel +Prototype: GG +Help: rnfidealabstorel(rnf,x): transforms the ideal x from absolute to + relative representation. +Doc: let $\var{rnf}$ be a relative + number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be an + ideal of the absolute extension $L/\Q$. Returns the relative pseudo-matrix in + HNF giving the ideal $x$ considered as an ideal of the relative extension + $L/K$, i.e.~as a $\Z_{K}$-module. + + Let \kbd{Labs} be an (absolute) \kbd{nf} structure attached to $L$, + obtained via \kbd{Labs = nfinit(rnf))}. Then \kbd{rnf} ``knows'' about + \kbd{Labs} and $x$ may be given in any format + attached to \kbd{Labs}, e.g. a prime ideal or an ideal in HNF wrt. + \kbd{Labs.zk}: + \bprog + ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); Labs = nfinit(rnf); + ? m = idealhnf(Labs, 17, x^3+2); \\ some ideal in HNF wrt. Labs.zk + ? B = rnfidealabstorel(rnf, m) + %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] \\ pseudo-basis for m as Z_K-module + ? A = rnfidealreltoabs(rnf, B) + %4 = [17, x^2 + 4, x + 8, x^3 + 8*x^2] \\ Z-basis for m in Q[x]/(rnf.polabs) + ? mathnf(matalgtobasis(Labs, A)) == m + %5 = 1 + @eprog\noindent If on the other hand, we do not have a \kbd{Labs} at hand, + because it would be too expensive to compute, but we nevertheless have + a $\Z$-basis for $x$, then we can use the function with this basis as + argument. The entries of $x$ may be given either modulo \kbd{rnf.polabs} + (absolute form, possibly lifted) or modulo \kbd{rnf.pol} (relative form as + \typ{POLMOD}s): + \bprog + ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); + ? rnfidealabstorel(rnf, [17, x^2 + 4, x + 8, x^3 + 8*x^2]) + %2 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] + ? rnfidealabstorel(rnf, Mod([17, y + 4, x + 8, y*x + 8*y], x^2-y)) + %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] + @eprog + +Function: rnfidealdown +Class: basic +Section: number_fields +C-Name: rnfidealdown +Prototype: GG +Help: rnfidealdown(rnf,x): finds the intersection of the ideal x with the + base field. +Doc: let $\var{rnf}$ be a relative number + field extension $L/K$ as output by \kbd{rnfinit}, and $x$ an ideal of + $L$, given either in relative form or by a $\Z$-basis of elements of $L$ + (see \secref{se:rnfidealabstorel}). This function returns the ideal of $K$ + below $x$, i.e.~the intersection of $x$ with $K$. + +Function: rnfidealfactor +Class: basic +Section: number_fields +C-Name: rnfidealfactor +Prototype: GG +Help: rnfidealfactor(rnf,x): factor the ideal x into + prime ideals in the number field nfinit(rnf). +Doc: factor into prime ideal powers the + ideal $x$ in the attached absolute number field $L = \kbd{nfinit}(\var{rnf})$. + The output format is similar to the \kbd{factor} function, and the prime + ideals are represented in the form output by the \kbd{idealprimedec} + function for $L$. + \bprog + ? rnf = rnfinit(nfinit(y^2+1), x^2-y+1); + ? rnfidealfactor(rnf, y+1) \\ P_2^2 + %2 = + [[2, [0,0,1,0]~, 4, 1, [0,0,0,2;0,0,-2,0;-1,-1,0,0;1,-1,0,0]] 2] + + ? rnfidealfactor(rnf, x) \\ P_2 + %3 = + [[2, [0,0,1,0]~, 4, 1, [0,0,0,2;0,0,-2,0;-1,-1,0,0;1,-1,0,0]] 1] + + ? L = nfinit(rnf); + ? id = idealhnf(L, idealhnf(L, 25, (x+1)^2)); + ? idealfactor(L, id) == rnfidealfactor(rnf, id) + %6 = 1 + @eprog\noindent Note that ideals of the base field $K$ must be explicitly + lifted to $L$ via \kbd{rnfidealup} before they can be factored. + +Function: rnfidealhnf +Class: basic +Section: number_fields +C-Name: rnfidealhnf +Prototype: GG +Help: rnfidealhnf(rnf,x): relative version of idealhnf, where rnf is a + relative numberfield. +Doc: $\var{rnf}$ being a relative number + field extension $L/K$ as output by \kbd{rnfinit} and $x$ being a relative + ideal (which can be, as in the absolute case, of many different types, + including of course elements), computes the HNF pseudo-matrix attached to + $x$, viewed as a $\Z_{K}$-module. + +Function: rnfidealmul +Class: basic +Section: number_fields +C-Name: rnfidealmul +Prototype: GGG +Help: rnfidealmul(rnf,x,y): relative version of idealmul, where rnf is a + relative numberfield. +Doc: $\var{rnf}$ being a relative number + field extension $L/K$ as output by \kbd{rnfinit} and $x$ and $y$ being ideals + of the relative extension $L/K$ given by pseudo-matrices, outputs the ideal + product, again as a relative ideal. + +Function: rnfidealnormabs +Class: basic +Section: number_fields +C-Name: rnfidealnormabs +Prototype: GG +Help: rnfidealnormabs(rnf,x): absolute norm of the ideal x. +Doc: let $\var{rnf}$ be a relative + number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a + relative ideal (which can be, as in the absolute case, of many different + types, including of course elements). This function computes the norm of the + $x$ considered as an ideal of the absolute extension $L/\Q$. This is + identical to + \bprog + idealnorm(rnf, rnfidealnormrel(rnf,x)) + @eprog\noindent but faster. + +Function: rnfidealnormrel +Class: basic +Section: number_fields +C-Name: rnfidealnormrel +Prototype: GG +Help: rnfidealnormrel(rnf,x): relative norm of the ideal x. +Doc: let $\var{rnf}$ be a relative + number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a + relative ideal (which can be, as in the absolute case, of many different + types, including of course elements). This function computes the relative + norm of $x$ as an ideal of $K$ in HNF. + +Function: rnfidealprimedec +Class: basic +Section: number_fields +C-Name: rnfidealprimedec +Prototype: GG +Help: rnfidealprimedec(rnf,pr): return prime ideal decomposition of the maximal + ideal pr of K in L/K; pr is also allowed to be a prime number p, in which + case return a pair of vectors [SK,SL], where SK contains the primes of K + above p and SL[i] is the vector of primes of L above SK[i]. +Doc: let \var{rnf} be a relative number + field extension $L/K$ as output by \kbd{rnfinit}, and \var{pr} a maximal + ideal of $K$ (\var{prid}), this function completes the \var{rnf} + with a \var{nf} structure attached to $L$ (see \secref{se:rnfinit}) + and returns the vector $S$ of prime ideals of $\Z_{L}$ above \var{pr}. + \bprog + ? K = nfinit(y^2+1); rnf = rnfinit(K, x^3+y+1); + ? pr = idealprimedec(K, 2)[1]; + ? S = rnfidealprimedec(rnf, pr); + ? #S + %4 = 1 + @eprog\noindent The relative ramification indices and residue degrees + can be obtained as \kbd{PR.e / pr.e} and \kbd{PR.f / PR.f}, if \kbd{PR} + is an element of $S$. + + The argument \var{pr} is also allowed to be a prime number $p$, in which + case the function returns a pair of vectors \kbd{[SK,SL]}, where \kbd{SK} + contains the primes of $K$ above $p$ and \kbd{SL}$[i]$ is the vector of primes + of $L$ above \kbd{SK}$[i]$. + \bprog + ? [SK,SL] = rnfidealprimedec(rnf, 5); + ? [#SK, vector(#SL,i,#SL[i])] + %6 = [2, [2, 2]] + @eprog + +Function: rnfidealreltoabs +Class: basic +Section: number_fields +C-Name: rnfidealreltoabs0 +Prototype: GGD0,L, +Help: rnfidealreltoabs(rnf,x,{flag=0}): transforms the ideal x from relative to + absolute representation. As a vector of t_POLMODs if flag = 0 and as an ideal + in HNF in the absolute field if flag = 1. +Doc: Let $\var{rnf}$ be a relative + number field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be a + relative ideal, given as a $\Z_{K}$-module by a pseudo matrix $[A,I]$. + This function returns the ideal $x$ as an absolute ideal of $L/\Q$. + If $\fl = 0$, the result is given by a vector of \typ{POLMOD}s modulo + \kbd{rnf.pol} forming a $\Z$-basis; if $\fl = 1$, it is given in HNF in terms + of the fixed $\Z$-basis for $\Z_{L}$, see \secref{se:rnfinit}. + \bprog + ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); + ? P = idealprimedec(K,2)[1]; + ? P = rnfidealup(rnf, P) + %3 = [2, x^2 + 1, 2*x, x^3 + x] + ? Prel = rnfidealhnf(rnf, P) + %4 = [[1, 0; 0, 1], [[2, 1; 0, 1], [2, 1; 0, 1]]] + ? rnfidealreltoabs(rnf,Prel) + %5 = [2, x^2 + 1, 2*x, x^3 + x] + ? rnfidealreltoabs(rnf,Prel,1) + %6 = + [2 1 0 0] + + [0 1 0 0] + + [0 0 2 1] + + [0 0 0 1] + @eprog + The reason why we do not return by default ($\fl = 0$) the customary HNF in + terms of a fixed $\Z$-basis for $\Z_{L}$ is precisely because + a \var{rnf} does not contain such a basis by default. Completing the + structure so that it contains a \var{nf} structure for $L$ is polynomial + time but costly when the absolute degree is large, thus it is not done by + default. Note that setting $\fl = 1$ will complete the \var{rnf}. +Variant: Also available is + \fun{GEN}{rnfidealreltoabs}{GEN rnf, GEN x} ($\fl = 0$). + +Function: rnfidealtwoelt +Class: basic +Section: number_fields +C-Name: rnfidealtwoelement +Prototype: GG +Help: rnfidealtwoelt(rnf,x): relative version of idealtwoelt, where rnf + is a relative numberfield. +Doc: $\var{rnf}$ being a relative + number field extension $L/K$ as output by \kbd{rnfinit} and $x$ being an + ideal of the relative extension $L/K$ given by a pseudo-matrix, gives a + vector of two generators of $x$ over $\Z_{L}$ expressed as polmods with polmod + coefficients. + +Function: rnfidealup +Class: basic +Section: number_fields +C-Name: rnfidealup0 +Prototype: GGD0,L, +Help: rnfidealup(rnf,x,{flag=0}): lifts the ideal x (of the base field) to the + relative field. As a vector of t_POLMODs if flag = 0 and as an ideal in HNF + in the absolute field if flag = 1. +Doc: let $\var{rnf}$ be a relative number + field extension $L/K$ as output by \kbd{rnfinit} and let $x$ be an ideal of + $K$. This function returns the ideal $x\Z_{L}$ as an absolute ideal of $L/\Q$, + in the form of a $\Z$-basis. If $\fl = 0$, the result is given by a vector of + polynomials (modulo \kbd{rnf.pol}); if $\fl = 1$, it is given in HNF in terms + of the fixed $\Z$-basis for $\Z_{L}$, see \secref{se:rnfinit}. + \bprog + ? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); + ? P = idealprimedec(K,2)[1]; + ? rnfidealup(rnf, P) + %3 = [2, x^2 + 1, 2*x, x^3 + x] + ? rnfidealup(rnf, P,1) + %4 = + [2 1 0 0] + + [0 1 0 0] + + [0 0 2 1] + + [0 0 0 1] + @eprog + The reason why we do not return by default ($\fl = 0$) the customary HNF in + terms of a fixed $\Z$-basis for $\Z_{L}$ is precisely because + a \var{rnf} does not contain such a basis by default. Completing the + structure so that it contains a \var{nf} structure for $L$ is polynomial + time but costly when the absolute degree is large, thus it is not done by + default. Note that setting $\fl = 1$ will complete the \var{rnf}. +Variant: Also available is + \fun{GEN}{rnfidealup}{GEN rnf, GEN x} ($\fl = 0$). + +Function: rnfinit +Class: basic +Section: number_fields +C-Name: rnfinit0 +Prototype: GGD0,L, +Help: rnfinit(nf,T,{flag=0}): T being an irreducible polynomial + defined over the number field nf, initializes a vector of data necessary for + working in relative number fields (rnf functions). See manual for technical + details. +Doc: given an \var{nf} structure attached to a number field $K$, as output by + \kbd{nfinit}, and a monic irreducible polynomial $T$ in $\Z_{K}[x]$ defining a + relative extension $L = K[x]/(T)$, this computes data to work in $L/K$ + The main variable of $T$ must be of higher priority + (see \secref{se:priority}) than that of $\var{nf}$, and the coefficients of + $T$ must be in $K$. + + The result is a row vector, whose components are technical. + We let $m = [K:\Q]$ the degree of the base field, $n = [L:K]$ the relative + degree, $r_{1}$ and $r_{2}$ the number of real and complex places of $K$. Access + to this information via \emph{member functions} is preferred since the + specific data organization specified below will change in the future. + + If $\fl = 1$, add an \var{nf} structure attached to $L$ to \var{rnf}. + This is likely to be very expensive if the absolute degree $mn$ is large, + but fixes an integer basis for $\Z_{L}$ as a $\Z$-module and allows to input + and output elements of $L$ in absolute form: as \typ{COL} for elements, + as \typ{MAT} in HNF for ideals, as \kbd{prid} for prime ideals. Without such + a call, elements of $L$ are represented as \typ{POLMOD}, etc. + Note that a subsequent \kbd{nfinit}$(\var{rnf})$ will also explicitly + add such a component, and so will the following functions \kbd{rnfidealmul}, + \kbd{rnfidealtwoelt}, \kbd{rnfidealprimedec}, \kbd{rnfidealup} (with flag 1) + and \kbd{rnfidealreltoabs} (with flag 1). The absolute \var{nf} structure + attached to $L$ can be recovered using \kbd{nfinit(rnf)}. + + $\var{rnf}[1]$(\kbd{rnf.pol}) contains the relative polynomial $T$. + + $\var{rnf}[2]$ contains the integer basis $[A,d]$ of $K$, as + (integral) elements of $L/\Q$. More precisely, $A$ is a vector of + polynomial with integer coefficients, $d$ is a denominator, and the integer + basis is given by $A/d$. + + $\var{rnf}[3]$ (\kbd{rnf.disc}) is a two-component row vector + $[\goth{d}(L/K),s]$ where $\goth{d}(L/K)$ is the relative ideal discriminant + of $L/K$ and $s$ is the discriminant of $L/K$ viewed as an element of + $K^{*}/(K^{*})^{2}$, in other words it is the output of \kbd{rnfdisc}. + + $\var{rnf}[4]$(\kbd{rnf.index}) is the ideal index $\goth{f}$, i.e.~such + that $d(T)\Z_{K}=\goth{f}^{2}\goth{d}(L/K)$. + + $\var{rnf}[5]$(\kbd{rnf.p}) is the list of rational primes dividing the norm + of the relative discriminant ideal. + + $\var{rnf}[7]$ (\kbd{rnf.zk}) is the pseudo-basis $(A,I)$ for the maximal + order $\Z_{L}$ as a $\Z_{K}$-module: $A$ is the relative integral pseudo basis + expressed as polynomials (in the variable of $T$) with polmod coefficients + in $\var{nf}$, and the second component $I$ is the ideal list of the + pseudobasis in HNF. + + $\var{rnf}[8]$ is the inverse matrix of the integral basis matrix, with + coefficients polmods in $\var{nf}$. + + $\var{rnf}[9]$ is currently unused. + + $\var{rnf}[10]$ (\kbd{rnf.nf}) is $\var{nf}$. + + $\var{rnf}[11]$ is an extension of \kbd{rnfequation(K, T, 1)}. Namely, a + vector $[P, a, k, \kbd{K.pol}, T]$ describing the \emph{absolute} + extension $L/\Q$: $P$ is an absolute equation, more conveniently obtained + as \kbd{rnf.polabs}; $a$ expresses the generator $\alpha = y \mod \kbd{K.pol}$ + of the number field $K$ as an element of $L$, i.e.~a polynomial modulo the + absolute equation $P$; + + $k$ is a small integer such that, if $\beta$ is an abstract root of $T$ + and $\alpha$ the generator of $K$ given above, then $P(\beta + k\alpha) = 0$. + It is guaranteed that $k = 0$ if $\Q(\beta) = L$. + + \misctitle{Caveat} Be careful if $k\neq0$ when dealing simultaneously with + absolute and relative quantities since $L = \Q(\beta + k\alpha) = + K(\alpha)$, and the generator chosen for the absolute extension is not the + same as for the relative one. If this happens, one can of course go on + working, but we advise to change the relative polynomial so that its root + becomes $\beta + k \alpha$. Typical GP instructions would be + \bprog + [P,a,k] = rnfequation(K, T, 1); + if (k, T = subst(T, x, x - k*Mod(y, K.pol))); + L = rnfinit(K, T); + @eprog + + $\var{rnf}[12]$ is by default unused and set equal to 0. This field is used + to store further information about the field as it becomes available (which + is rarely needed, hence would be too expensive to compute during the initial + \kbd{rnfinit} call). + + \misctitle{Huge discriminants, helping rnfdisc} When $T$ has a + discriminant which is difficult to factor, it is hard to compute + $\Z_{L}$. As in \kbd{nfinit}, the special input format $[T,B]$ + is also accepted, where $T$ is a polynomial as above and $B$ specifies a + list of maximal ideals. The following formats are recognized for $B$: + + \item an integer: the list of all maximal ideals above a rational + prime $p < B$. + + \item a vector of rational primes or prime ideals: the list of all maximal + ideals dividing an element in the list. + + Instead of $\Z_{L}$, this produces an order which is maximal at all such + maximal ideals primes. The result may actually be a complete and correct + \var{rnf} structure if the relative ideal discriminant factors completely + over this list of maximal ideals but this is not guaranteed. In general, the + order may not be maximal at primes $\goth{p}$ not in the list such that + $\goth{p}^{2}$ divides the relative ideal discriminant. +Variant: Also available is + \fun{GEN}{rnfinit}{GEN nf,GEN T} ($\fl = 0$). + +Function: rnfisabelian +Class: basic +Section: number_fields +C-Name: rnfisabelian +Prototype: lGG +Help: rnfisabelian(nf,T): T being a relative polynomial with coefficients + in nf, return 1 if it defines an abelian extension, and 0 otherwise. +Doc: $T$ being a relative polynomial with coefficients + in \var{nf}, return 1 if it defines an abelian extension, and 0 otherwise. + \bprog + ? K = nfinit(y^2 + 23); + ? rnfisabelian(K, x^3 - 3*x - y) + %2 = 1 + @eprog + +Function: rnfisfree +Class: basic +Section: number_fields +C-Name: rnfisfree +Prototype: lGG +Help: rnfisfree(bnf,M): given a bnf attached to a number field K and a + projective Z_K module M given by a pseudo-matrix, return true (1) if M + is free else return false (0). +Doc: given a $\var{bnf}$ attached to a number field $K$ and + a projective $\Z_{K}$-module $M$ given by a pseudo-matrix, return true (1) if + $M$ is free else return false (0). If $M$ is a polynomial with coefficients + in $K$, replace it by the pseudo-matrix returned by \kbd{rnfpseudobasis}. + +Function: rnfislocalcyclo +Class: basic +Section: number_fields +C-Name: rnfislocalcyclo +Prototype: lG +Help: rnfislocalcyclo(rnf): true(1) if the l-extension attached to rnf + is locally cyclotomic (locally contained in the Z_l extension of K_v at + all places v | l), false(0) if not. +Doc: Let \var{rnf} be a relative number field extension $L/K$ as output + by \kbd{rnfinit} whose degree $[L:K]$ is a power of a prime $\ell$. + Return $1$ if the $\ell$-extension is locally cyclotomic (locally contained in + the cyclotomic $\Z_{\ell}$-extension of $K_{v}$ at all places $v | \ell$), and + $0$ if not. + \bprog + ? K = nfinit(y^2 + y + 1); + ? L = rnfinit(K, x^3 - y); /* = K(zeta_9), globally cyclotomic */ + ? rnfislocalcyclo(L) + %3 = 1 + \\ we expect 3-adic continuity by Krasner's lemma + ? vector(5, i, rnfislocalcyclo(rnfinit(K, x^3 - y + 3^i))) + %5 = [0, 1, 1, 1, 1] + @eprog + +Function: rnfisnorm +Class: basic +Section: number_fields +C-Name: rnfisnorm +Prototype: GGD0,L, +Help: rnfisnorm(T,a,{flag=0}): T is as output by rnfisnorminit applied to + L/K. Tries to tell whether a is a norm from L/K. Returns a vector [x,q] + where a=Norm(x)*q. Looks for a solution which is a S-integer, with S a list + of places in K containing the ramified primes, generators of the class group + of ext, as well as those primes dividing a. If L/K is Galois, you may omit + flag, otherwise it is used to add more places to S: all the places above the + primes p <= flag (resp. p | flag) if flag > 0 (resp. flag < 0). The answer + is guaranteed (i.e a is a norm iff q=1) if L/K is Galois or, under GRH, if S + contains all primes less than 4log(disc(M))^2, where M is the normal + closure of L/K. +Doc: similar to + \kbd{bnfisnorm} but in the relative case. $T$ is as output by + \tet{rnfisnorminit} applied to the extension $L/K$. This tries to decide + whether the element $a$ in $K$ is the norm of some $x$ in the extension + $L/K$. + + The output is a vector $[x,q]$, where $a = \Norm(x)*q$. The + algorithm looks for a solution $x$ which is an $S$-integer, with $S$ a list + of places of $K$ containing at least the ramified primes, the generators of + the class group of $L$, as well as those primes dividing $a$. If $L/K$ is + Galois, then this is enough but you may want to add more primes to $S$ to + produce different elements, possibly smaller; otherwise, $\fl$ is used to + add more primes to $S$: all the places above the primes $p \leq \fl$ + (resp.~$p|\fl$) if $\fl>0$ (resp.~$\fl<0$). + + The answer is guaranteed (i.e.~$a$ is a norm iff $q = 1$) if the field is + Galois, or, under \idx{GRH}, if $S$ contains all primes less than + $4\log^{2}\left|\disc(M)\right|$, where $M$ is the normal + closure of $L/K$. + + If \tet{rnfisnorminit} has determined (or was told) that $L/K$ is + \idx{Galois}, and $\fl \neq 0$, a Warning is issued (so that you can set + $\fl = 1$ to check whether $L/K$ is known to be Galois, according to $T$). + Example: + + \bprog + bnf = bnfinit(y^3 + y^2 - 2*y - 1); + p = x^2 + Mod(y^2 + 2*y + 1, bnf.pol); + T = rnfisnorminit(bnf, p); + rnfisnorm(T, 17) + @eprog\noindent + checks whether $17$ is a norm in the Galois extension $\Q(\beta) / + \Q(\alpha)$, where $\alpha^{3} + \alpha^{2} - 2\alpha - 1 = 0$ and + $\beta^{2} + \alpha^{2} + 2\alpha + 1 = 0$ (it is). + +Function: rnfisnorminit +Class: basic +Section: number_fields +C-Name: rnfisnorminit +Prototype: GGD2,L, +Help: rnfisnorminit(pol,polrel,{flag=2}): let K be defined by a root of pol, + L/K the extension defined by polrel. Compute technical data needed by + rnfisnorm to solve norm equations Nx = a, for x in L, and a in K. If flag=0, + do not care whether L/K is Galois or not; if flag = 1, assume L/K is Galois; + if flag = 2, determine whether L/K is Galois. +Doc: let $K$ be defined by a root of \var{pol}, and $L/K$ the extension defined + by the polynomial \var{polrel}. As usual, \var{pol} can in fact be an \var{nf}, + or \var{bnf}, etc; if \var{pol} has degree $1$ (the base field is $\Q$), + polrel is also allowed to be an \var{nf}, etc. Computes technical data needed + by \tet{rnfisnorm} to solve norm equations $Nx = a$, for $x$ in $L$, and $a$ + in $K$. + + If $\fl = 0$, do not care whether $L/K$ is Galois or not. + + If $\fl = 1$, $L/K$ is assumed to be Galois (unchecked), which speeds up + \tet{rnfisnorm}. + + If $\fl = 2$, let the routine determine whether $L/K$ is Galois. + +Function: rnfkummer +Class: basic +Section: number_fields +C-Name: rnfkummer +Prototype: GDGp +Obsolete: 2020-05-22 +Help: rnfkummer(bnr,{subgp}): this function is deprecated. Use bnrclassfield. +Doc: This function is deprecated, use \kbd{bnrclassfield}. + +Function: rnflllgram +Class: basic +Section: number_fields +C-Name: rnflllgram +Prototype: GGGp +Help: rnflllgram(nf,pol,order): given a pol with coefficients in nf and an + order as output by rnfpseudobasis or similar, gives [[neworder],U], where + neworder is a reduced order and U is the unimodular transformation matrix. +Doc: given a polynomial + \var{pol} with coefficients in \var{nf} defining a relative extension $L$ and + a suborder \var{order} of $L$ (of maximal rank), as output by + \kbd{rnfpseudobasis}$(\var{nf},\var{pol})$ or similar, gives + $[[\var{neworder}],U]$, where \var{neworder} is a reduced order and $U$ is + the unimodular transformation matrix. + +Function: rnfnormgroup +Class: basic +Section: number_fields +C-Name: rnfnormgroup +Prototype: GG +Help: rnfnormgroup(bnr,pol): norm group (or Artin or Takagi group) + corresponding to the Abelian extension of bnr.bnf defined by pol, where + the module corresponding to bnr is assumed to be a multiple of the + conductor. The result is the HNF defining the norm group on the + generators in bnr.gen. +Doc: + \var{bnr} being a big ray + class field as output by \kbd{bnrinit} and \var{pol} a relative polynomial + defining an \idx{Abelian extension}, computes the norm group (alias Artin + or Takagi group) corresponding to the Abelian extension of + $\var{bnf}=$\kbd{bnr.bnf} + defined by \var{pol}, where the module corresponding to \var{bnr} is assumed + to be a multiple of the conductor (i.e.~\var{pol} defines a subextension of + bnr). The result is the HNF defining the norm group on the given generators + of \kbd{bnr.gen}. Note that neither the fact that \var{pol} defines an + Abelian extension nor the fact that the module is a multiple of the conductor + is checked. The result is undefined if the assumption is not correct, + but the function will return the empty matrix \kbd{[;]} if it detects a + problem; it may also not detect the problem and return a wrong result. + +Function: rnfpolred +Class: basic +Section: number_fields +C-Name: rnfpolred +Prototype: GGp +Obsolete: 2013-12-28 +Help: rnfpolred(nf,pol): given a pol with coefficients in nf, finds a list + of relative polynomials defining some subfields, hopefully simpler. +Doc: This function is obsolete: use \tet{rnfpolredbest} instead. + Relative version of \kbd{polred}. Given a monic polynomial \var{pol} with + coefficients in $\var{nf}$, finds a list of relative polynomials defining some + subfields, hopefully simpler and containing the original field. In the present + version \vers, this is slower and less efficient than \kbd{rnfpolredbest}. + + \misctitle{Remark} This function is based on an incomplete reduction + theory of lattices over number fields, implemented by \kbd{rnflllgram}, which + deserves to be improved. + +Function: rnfpolredabs +Class: basic +Section: number_fields +C-Name: rnfpolredabs +Prototype: GGD0,L, +Help: rnfpolredabs(nf,pol,{flag=0}): given an irreducible pol with coefficients + in nf, finds a canonical relative polynomial defining the same field. + Binary digits of flag mean: 1: return also the element whose characteristic + polynomial is the given polynomial, 2: return an absolute polynomial, + 16: partial reduction. +Doc: Relative version of \kbd{polredabs}. Given an irreducible monic polynomial + \var{pol} with coefficients in the maximal order of $\var{nf}$, finds a + canonical relative + polynomial defining the same field, hopefully with small coefficients. + Note that the equation is only canonical for a fixed \var{nf}, using a + different defining polynomial in the \var{nf} structure will produce a + different relative equation. + + The binary digits of $\fl$ correspond to $1$: add information to convert + elements to the new representation, $2$: absolute polynomial, instead of + relative, $16$: possibly use a suborder of the maximal order. More precisely: + + 0: default, return $P$ + + 1: returns $[P,a]$ where $P$ is the default output and $a$, + a \typ{POLMOD} modulo $P$, is a root of \var{pol}. + + 2: returns \var{Pabs}, an absolute, instead of a relative, polynomial. + This polynomial is canonical and does not depend on the \var{nf} structure. + Same as but faster than + \bprog + polredabs(rnfequation(nf, pol)) + @eprog + + 3: returns $[\var{Pabs},a,b]$, where \var{Pabs} is an absolute polynomial + as above, $a$, $b$ are \typ{POLMOD} modulo \var{Pabs}, roots of \kbd{nf.pol} + and \var{pol} respectively. + + 16: (OBSOLETE) possibly use a suborder of the maximal order. This makes + \kbd{rnfpolredabs} behave as \kbd{rnfpolredbest}. Just use the latter. + + \misctitle{Warning} The complexity of \kbd{rnfpolredabs} + is exponential in the absolute degree. The function \tet{rnfpolredbest} runs + in polynomial time, and tends to return polynomials with smaller + discriminants. It also supports polynomials with arbitrary coefficients in + \var{nf}, neither integral nor necessarily monic. + +Function: rnfpolredbest +Class: basic +Section: number_fields +C-Name: rnfpolredbest +Prototype: GGD0,L, +Help: rnfpolredbest(nf,pol,{flag=0}): given a pol with coefficients in nf, + finds a relative polynomial P defining the same field, hopefully simpler + than pol; flag + can be 0: default, 1: return [P,a], where a is a root of pol + 2: return an absolute polynomial Pabs, 3: + return [Pabs, a,b], where a is a root of nf.pol and b is a root of pol. +Doc: relative version of \kbd{polredbest}. Given a polynomial \var{pol} + with coefficients in $\var{nf}$, finds a simpler relative polynomial $P$ + defining the same field. As opposed to \tet{rnfpolredabs} this function does + not return a \emph{smallest} (canonical) polynomial with respect to some + measure, but it does run in polynomial time. + + The binary digits of $\fl$ correspond to $1$: add information to convert + elements to the new representation, $2$: absolute polynomial, instead of + relative. More precisely: + + 0: default, return $P$ + + 1: returns $[P,a]$ where $P$ is the default output and $a$, + a \typ{POLMOD} modulo $P$, is a root of \var{pol}. + + 2: returns \var{Pabs}, an absolute, instead of a relative, polynomial. + Same as but faster than + \bprog + rnfequation(nf, rnfpolredbest(nf,pol)) + @eprog + + 3: returns $[\var{Pabs},a,b]$, where \var{Pabs} is an absolute polynomial + as above, $a$, $b$ are \typ{POLMOD} modulo \var{Pabs}, roots of \kbd{nf.pol} + and \var{pol} respectively. + + \bprog + ? K = nfinit(y^3-2); pol = x^2 +x*y + y^2; + ? [P, a] = rnfpolredbest(K,pol,1); + ? P + %3 = x^2 - x + Mod(y - 1, y^3 - 2) + ? a + %4 = Mod(Mod(2*y^2+3*y+4,y^3-2)*x + Mod(-y^2-2*y-2,y^3-2), + x^2 - x + Mod(y-1,y^3-2)) + ? subst(K.pol,y,a) + %5 = 0 + ? [Pabs, a, b] = rnfpolredbest(K,pol,3); + ? Pabs + %7 = x^6 - 3*x^5 + 5*x^3 - 3*x + 1 + ? a + %8 = Mod(-x^2+x+1, x^6-3*x^5+5*x^3-3*x+1) + ? b + %9 = Mod(2*x^5-5*x^4-3*x^3+10*x^2+5*x-5, x^6-3*x^5+5*x^3-3*x+1) + ? subst(K.pol,y,a) + %10 = 0 + ? substvec(pol,[x,y],[a,b]) + %11 = 0 + @eprog + +Function: rnfpseudobasis +Class: basic +Section: number_fields +C-Name: rnfpseudobasis +Prototype: GG +Help: rnfpseudobasis(nf,T): given an irreducible polynomial T with + coefficients in nf, returns [A,J,D,d] where [A,J] is a pseudo basis of the + maximal order of the extension, D is the relative ideal discriminant, and d + is the relative discriminant in nf^*/nf*^2. +Doc: given an \var{nf} structure attached to a number field $K$, as output by + \kbd{nfinit}, and a monic irreducible polynomial $T$ in $\Z_{K}[x]$ defining a + relative extension $L = K[x]/(T)$, computes the relative discriminant of $L$ + and a pseudo-basis $(A,J)$ for the maximal order $\Z_{L}$ viewed as a + $\Z_{K}$-module. This is output as a vector $[A,J,D,d]$, where $D$ is the + relative ideal discriminant and $d$ is the relative discriminant considered + as an element of $K^{*}/{K^{*}}^{2}$. + \bprog + ? K = nfinit(y^2+1); + ? [A,J,D,d] = rnfpseudobasis(K, x^2+y); + ? A + %3 = + [1 0] + + [0 1] + + ? J + %4 = [1, 1] + ? D + %5 = [0, -4]~ + ? d + %6 = [0, -1]~ + @eprog + + \misctitle{Huge discriminants, helping rnfdisc} The format $[T,B]$ is + also accepted instead of $T$ and produce an order which is maximal at all + prime ideals specified by $B$, see \kbd{??rnfinit}. + \bprog + ? p = 585403248812100232206609398101; + ? q = 711171340236468512951957953369; + ? T = x^2 + 3*(p*q)^2; + ? [A,J,D,d] = V = rnfpseudobasis(K, T); D + time = 22,178 ms. + %10 = 3 + ? [A,J,D,d] = W = rnfpseudobasis(K, [T,100]); D + time = 5 ms. + %11 = 3 + ? V == W + %12 = 1 + ? [A,J,D,d] = W = rnfpseudobasis(K, [T, [3]]); D + %13 = 3 + ? V == W + %14 = 1 + @eprog\noindent In this example, the results are identical since $D \cap \Z$ + factors over primes less than $100$ (and in fact, over $3$). Had it not been + the case, the order would have been guaranteed maximal at primes + $\goth{p} | p $ for $p \leq 100$ only (resp.~$\goth{p} | 3$). + And might have been nonmaximal at any other prime ideal $\goth{p}$ such + that $\goth{p}^{2}$ divided $D$. + +Function: rnfsteinitz +Class: basic +Section: number_fields +C-Name: rnfsteinitz +Prototype: GG +Help: rnfsteinitz(nf,M): given a nf attached to a number field K and a + projective module M given by a pseudo-matrix, returns [A,I,D,d] where (A,I) + is a pseudo basis for M where all the ideals except perhaps the last are + trivial. If M is a polynomial with coefficients in K, replace it by the + pseudo-matrix returned by rnfpseudobasis. +Doc: given a $\var{nf}$ attached to a number field $K$ and a projective + module $M$ given by a pseudo-matrix, returns a pseudo-basis $(A,I)$ + (not in HNF in general) such that all the ideals of $I$ except perhaps the + last one are equal to the ring of integers of $\var{nf}$. If $M$ is a + polynomial with coefficients in $K$, replace it by the pseudo-matrix + returned by \kbd{rnfpseudobasis} and return the four-component row vector + $[A,I,D,d]$ where $(A,I)$ are as before and $(D,d)$ are discriminants + as returned by \kbd{rnfpseudobasis}. The ideal class of the last ideal of + $I$ is well defined; it is the \idx{Steinitz class} of $M$ (its image + in $SK_{0}(\Z_{K})$). + +Function: rootsof1 +Class: basic +Section: transcendental +C-Name: grootsof1 +Prototype: Lp +Help: rootsof1(N): column vector of complex N-th roots of 1. +Doc: return the column vector $v$ of all complex $N$-th roots of $1$, where $N$ + is a positive integer. In other words, + $v[k] = \exp(2I(k-1)\pi/N)$ for $k = 1, \dots, N$. Rational components + (e.g., the roots $\pm1$ and $\pm I$) are given exactly, not as floating point + numbers: + \bprog + ? rootsof1(4) + %1 = [1, I, -1, -I]~ + ? rootsof1(3) + %2 = [1, -1/2 + 0.866025...*I, -1/2 - 0.866025...*I]~ + @eprog + +Function: round +Class: basic +Section: conversions +C-Name: round0 +Prototype: GD& +Help: round(x,{&e}): take the nearest integer to all the coefficients of x. + If e is present, do not take into account loss of integer part precision, + and set e = error estimate in bits. +Description: + (small):small:parens $1 + (int):int:copy:parens $1 + (real):int roundr($1) + (mp):int mpround($1) + (mp, &small):int grndtoi($1, &$2) + (mp, &int):int round0($1, &$2) + (gen):gen ground($1) + (gen, &small):gen grndtoi($1, &$2) + (gen, &int):gen round0($1, &$2) +Doc: If $x$ is in $\R$, rounds $x$ to the nearest integer (rounding to + $+\infty$ in case of ties), then sets $e$ to the number of error bits, + that is the binary exponent of the difference between the original and the + rounded value (the ``fractional part''). If the exponent of $x$ is too large + compared to its precision (i.e.~$e>0$), the result is undefined and an error + occurs if $e$ was not given. + + \misctitle{Important remark} Contrary to the other truncation functions, + this function operates on every coefficient at every level of a PARI object. + For example + $$\text{truncate}\left(\dfrac{2.4*X^{2}-1.7}{X}\right)=2.4*X,$$ + whereas + $$\text{round}\left(\dfrac{2.4*X^{2}-1.7}{X}\right)=\dfrac{2*X^{2}-2}{X}.$$ + An important use of \kbd{round} is to get exact results after an approximate + computation, when theory tells you that the coefficients must be integers. +Variant: Also available are \fun{GEN}{grndtoi}{GEN x, long *e} and + \fun{GEN}{ground}{GEN x}. + +Function: select +Class: basic +Section: programming/specific +C-Name: select0 +Prototype: GGD0,L, +Help: select(f,A,{flag=0}): selects elements of A according to the selection + function f. If flag is 1, return the indices of those elements (indirect + selection). +Wrapper: (bG) +Description: + (gen,gen):gen genselect(${1 cookie}, ${1 wrapper}, $2) + (gen,gen,0):gen genselect(${1 cookie}, ${1 wrapper}, $2) + (gen,gen,1):vecsmall genindexselect(${1 cookie}, ${1 wrapper}, $2) +Doc: We first describe the default behavior, when $\fl$ is 0 or omitted. + Given a vector or list \kbd{A} and a \typ{CLOSURE} \kbd{f}, \kbd{select} + returns the elements $x$ of \kbd{A} such that $f(x)$ is nonzero. In other + words, \kbd{f} is seen as a selection function returning a boolean value. + \bprog + ? select(x->isprime(x), vector(50,i,i^2+1)) + %1 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] + ? select(x->(x<100), %) + %2 = [2, 5, 17, 37] + @eprog\noindent returns the primes of the form $i^{2}+1$ for some $i\leq 50$, + then the elements less than 100 in the preceding result. The \kbd{select} + function also applies to a matrix \kbd{A}, seen as a vector of columns, i.e. it + selects columns instead of entries, and returns the matrix whose columns are + the selected ones. + + \misctitle{Remark} For $v$ a \typ{VEC}, \typ{COL}, \typ{VECSMALL}, + \typ{LIST} or \typ{MAT}, the alternative set-notations + \bprog + [g(x) | x <- v, f(x)] + [x | x <- v, f(x)] + [g(x) | x <- v] + @eprog\noindent + are available as shortcuts for + \bprog + apply(g, select(f, Vec(v))) + select(f, Vec(v)) + apply(g, Vec(v)) + @eprog\noindent respectively: + \bprog + ? [ x | x <- vector(50,i,i^2+1), isprime(x) ] + %1 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] + @eprog + + \noindent If $\fl = 1$, this function returns instead the \emph{indices} of + the selected elements, and not the elements themselves (indirect selection): + \bprog + ? V = vector(50,i,i^2+1); + ? select(x->isprime(x), V, 1) + %2 = Vecsmall([1, 2, 4, 6, 10, 14, 16, 20, 24, 26, 36, 40]) + ? vecextract(V, %) + %3 = [2, 5, 17, 37, 101, 197, 257, 401, 577, 677, 1297, 1601] + @eprog\noindent + The following function lists the elements in $(\Z/N\Z)^{*}$: + \bprog + ? invertibles(N) = select(x->gcd(x,N) == 1, [1..N]) + @eprog + + \noindent Finally + \bprog + ? select(x->x, M) + @eprog\noindent selects the nonzero entries in \kbd{M}. If the latter is a + \typ{MAT}, we extract the matrix of nonzero columns. Note that \emph{removing} + entries instead of selecting them just involves replacing the selection + function \kbd{f} with its negation: + \bprog + ? select(x->!isprime(x), vector(50,i,i^2+1)) + @eprog + + \synt{genselect}{void *E, long (*fun)(void*,GEN), GEN a}. Also available + is \fun{GEN}{genindexselect}{void *E, long (*fun)(void*, GEN), GEN a}, + corresponding to $\fl = 1$. + +Function: self +Class: basic +Section: programming/specific +C-Name: pari_self +Prototype: m +Help: self(): return the calling function or closure. Useful for defining + anonymous recursive functions. +Doc: return the calling function or closure as a \typ{CLOSURE} object. + This is useful for defining anonymous recursive functions. + \bprog + ? (n -> if(n==0,1,n*self()(n-1)))(5) + %1 = 120 \\ 5! + + ? (n -> if(n<=1, n, self()(n-1)+self()(n-2)))(20) + %2 = 6765 \\ Fibonacci(20) + @eprog + +Function: seralgdep +Class: basic +Section: polynomials +C-Name: seralgdep +Prototype: GLL +Help: seralgdep(s,p,r): find a linear relation between powers (1,s, ..., s^p) + of the series s, with polynomial coefficients of degree <= r. +Doc: \sidx{algebraic dependence} finds a linear relation between powers $(1,s, + \dots, s^{p})$ of the series $s$, with polynomial coefficients of degree + $\leq r$. In case no relation is found, return $0$. + \bprog + ? s = 1 + 10*y - 46*y^2 + 460*y^3 - 5658*y^4 + 77740*y^5 + O(y^6); + ? seralgdep(s, 2, 2) + %2 = -x^2 + (8*y^2 + 20*y + 1) + ? subst(%, x, s) + %3 = O(y^6) + ? seralgdep(s, 1, 3) + %4 = (-77*y^2 - 20*y - 1)*x + (310*y^3 + 231*y^2 + 30*y + 1) + ? seralgdep(s, 1, 2) + %5 = 0 + @eprog\noindent The series main variable must not be $x$, so as to be able + to express the result as a polynomial in $x$. + +Function: serchop +Class: basic +Section: conversions +C-Name: serchop +Prototype: GD0,L, +Help: serchop(s,{n=0}): remove all terms of degree strictly less than n in + series s. +Doc: remove all terms of degree strictly less than $n$ in series $s$. When + the series contains no terms of degree $< n$, return $O(x^{n})$. + \bprog + ? s = 1/x + x + 2*x^2 + O(x^3); + ? serchop(s) + %2 = x + 2*x^3 + O(x^3) + ? serchop(s, 2) + %3 = 2*x^2 + O(x^3) + ? serchop(s, 100) + %4 = O(x^100) + @eprog + +Function: serconvol +Class: basic +Section: polynomials +C-Name: convol +Prototype: GG +Help: serconvol(x,y): convolution (or Hadamard product) of two power series. +Doc: convolution (or \idx{Hadamard product}) of the + two power series $x$ and $y$; in other words if $x=\sum a_{k}*X^{k}$ + and $y=\sum b_{k}*X^{k}$ then $\kbd{serconvol}(x,y)=\sum a_{k}*b_{k}*X^{k}$. + +Function: serdiffdep +Class: basic +Section: polynomials +C-Name: serdiffdep +Prototype: GLL +Help: serdiffdep(s,p,r): find an inhomogenous linear differential equation + satisfied by the series s, with polynomial coefficients of degree <= r. The + result is a pair [E,P] such that E(d)(S)=P where E(d) is interpreted as a + differential polynomial, or 0 in case no relation is found. +Doc: find a linear relation between the derivatives $(s, s', \dots, s^{p})$ of + the series $s$ and $1$, with polynomial coefficients of degree $\leq r$. In + case no relation is found, return $0$, otherwise return $[E,P]$ such that + $E(d)(S)=P$ where $d$ is the standard derivation. + \bprog + ? S = sum(i=0, 50, binomial(3*i,i)*T^i) + O(T^51); + ? serdiffdep(S, 3, 3) + %2 = [(27*T^2 - 4*T)*x^2 + (54*T - 2)*x + 6, 0] + ? (27*T^2 - 4*T)*S'' + (54*T - 2)*S' + 6*S + %3 = O(T^50) + + ? S = exp(T^2) + T^2; + ? serdiffdep(S, 3, 3) + %5 = [x-2*T, -2*T^3+2*T] + ? S'-2*T*S + %6 = 2*T-2*T^3+O(T^17) + @eprog \noindent The series main variable must not be $x$, so as to be able + to express the result as a polynomial in $x$. + +Function: serlaplace +Class: basic +Section: polynomials +C-Name: laplace +Prototype: G +Help: serlaplace(x): replaces the power series sum of a_n*x^n/n! by sum of + a_n*x^n. For the reverse operation, use serconvol(x,exp(X)). +Doc: $x$ must be a power series with nonnegative + exponents or a polynomial. If $x=\sum (a_{k}/k!)*X^{k}$ then the result isi + $\sum a_{k}*X^{k}$. + +Function: serprec +Class: basic +Section: conversions +C-Name: gpserprec +Prototype: Gn +Help: serprec(x,v): + return the absolute precision x with respect to power series in the variable v. +Doc: returns the absolute precision of $x$ with respect to power series + in the variable $v$; this is the + minimum precision of the components of $x$. The result is \tet{+oo} if $x$ + is an exact object (as a series in $v$): + \bprog + ? serprec(x + O(y^2), y) + %1 = 2 + ? serprec(x + 2, x) + %2 = +oo + ? serprec(2 + x + O(x^2), y) + %3 = +oo + @eprog +Variant: Also available is \fun{long}{serprec}{GEN x, GEN p}, which returns + \tet{LONG_MAX} if $x = 0$, otherwise the series precision as a \kbd{long} integer. + +Function: serreverse +Class: basic +Section: polynomials +C-Name: serreverse +Prototype: G +Help: serreverse(s): reversion of the power series s. +Doc: reverse power series of $s$, i.e. the series $t$ such that $t(s) = x$; + $s$ must be a power series whose valuation is exactly equal to one. + \bprog + ? \ps 8 + ? t = serreverse(tan(x)) + %2 = x - 1/3*x^3 + 1/5*x^5 - 1/7*x^7 + O(x^8) + ? tan(t) + %3 = x + O(x^8) + @eprog + +Function: setbinop +Class: basic +Section: linear_algebra +C-Name: setbinop +Prototype: GGDG +Help: setbinop(f,X,{Y}): the set {f(x,y), x in X, y in Y}. If Y is omitted, + assume that X = Y and that f is symmetric. +Doc: the set whose elements are the f(x,y), where x,y run through X,Y. + respectively. If $Y$ is omitted, assume that $X = Y$ and that $f$ is symmetric: + $f(x,y) = f(y,x)$ for all $x,y$ in $X$. + \bprog + ? X = [1,2,3]; Y = [2,3,4]; + ? setbinop((x,y)->x+y, X,Y) \\ set X + Y + %2 = [3, 4, 5, 6, 7] + ? setbinop((x,y)->x-y, X,Y) \\ set X - Y + %3 = [-3, -2, -1, 0, 1] + ? setbinop((x,y)->x+y, X) \\ set 2X = X + X + %2 = [2, 3, 4, 5, 6] + @eprog + +Function: setdebug +Class: basic +Section: programming/control +C-Name: setdebug +Prototype: DsD-1,L, +Help: setdebug({D},{n}): + sets debug level for domain D to n (n must be between 0 and 20). + If n is omitted, returns the current level for domain D. + if D is omitted, returns a two-column matrix which lists the available domains + with their levels. +Doc: sets debug level for domain $D$ to $n$ ($0 \leq n \leq 20$). + The domain $D$ is a character string describing a Pari feature or code + module, such as \kbd{"bnf"}, \kbd{"qflll"} or \kbd{"polgalois"}. This allows + to selectively increase or decrease the diagnostics attached to a particular + feature. + If $n$ is omitted, returns the current level for domain $D$. + If $D$ is omitted, returns a two-column matrix which lists the available + domains with their levels. The \kbd{debug} default allows to reset all debug + levels to a given value. + \bprog + ? setdebug()[,1] \\ list of all domains + ["alg", "arith", "bern", "bnf", "bnr", "bnrclassfield", ..., "zetamult"] + + ? \g 1 \\ sets all debug levels to 1 + debug = 1 + ? setdebug("bnf", 0); \\ kills messages related to bnfinit and bnfisrincipal + @eprog +Variant: Also available is + \fun{void}{setalldebug}{long n}: sets all debug domains to level \var{n}. + +Function: setdelta +Class: basic +Section: linear_algebra +C-Name: setdelta +Prototype: GG +Help: setdelta(x,y): symmetric difference of the sets x and y. +Description: + (vec, vec):vec setdelta($1, $2) +Doc: symmetric difference of the two sets $x$ and $y$ (see \kbd{setisset}). + If $x$ or $y$ is not a set, the result is undefined. + \bprog + ? a=[1,2,2,3];b=[4,2,3,4]; + ? setdelta(Set(a), Set(b)) + %2 = [1, 4] \\ the symmetric difference of the two sets + ? setdelta(a,b) + %3 = [1, 2, 2, 3, 4, 2, 3, 4] \\ undefined result + @eprog + +Function: setintersect +Class: basic +Section: linear_algebra +C-Name: setintersect +Prototype: GG +Help: setintersect(x,y): intersection of the sets x and y. +Description: + (vec, vec):vec setintersect($1, $2) +Doc: intersection of the two sets $x$ and $y$ (see \kbd{setisset}). + If $x$ or $y$ is not a set, the result is undefined. + +Function: setisset +Class: basic +Section: linear_algebra +C-Name: setisset +Prototype: lG +Help: setisset(x): true(1) if x is a set (row vector with strictly + increasing entries), false(0) if not. +Doc: + returns true (1) if $x$ is a set, false (0) if + not. In PARI, a set is a row vector whose entries are strictly + increasing with respect to a (somewhat arbitrary) universal comparison + function. To convert any object into a set (this is most useful for + vectors, of course), use the function \kbd{Set}. + \bprog + ? a = [3, 1, 1, 2]; + ? setisset(a) + %2 = 0 + ? Set(a) + %3 = [1, 2, 3] + @eprog + +Function: setminus +Class: basic +Section: linear_algebra +C-Name: setminus +Prototype: GG +Help: setminus(x,y): set of elements of x not belonging to y. +Description: + (vec, vec):vec setminus($1, $2) +Doc: difference of the two sets $x$ and $y$ (see \kbd{setisset}), + i.e.~set of elements of $x$ which do not belong to $y$. + If $x$ or $y$ is not a set, the result is undefined. + +Function: setrand +Class: basic +Section: programming/specific +C-Name: setrand +Prototype: vG +Help: setrand(n): reset the seed of the random number generator to n. +Doc: reseeds the random number generator using the seed $n$. No value is + returned. The seed is a small positive integer $0 < n < 2^{64}$ used to + generate deterministically a suitable state array. All gp session start + by an implicit \kbd{setrand(1)}, so resetting the seed to this value allows + to replay all computations since the session start. Alternatively, + running a randomized computation starting by \kbd{setrand}($n$) + twice with the same $n$ will generate the exact same output. + + In the other direction, including a call to \kbd{setrand(getwalltime())} + from your gprc will cause GP to produce different streams of random numbers + in each session. (Unix users may want to use \kbd{/dev/urandom} instead + of \kbd{getwalltime}.) + + For debugging purposes, one can also record a particular random state + using \kbd{getrand} (the value is encoded as a huge integer) and feed it to + \kbd{setrand}: + \bprog + ? state = getrand(); \\ record seed + ... + ? setrand(state); \\ we can now replay the exact same computations + @eprog + +Function: setsearch +Class: basic +Section: linear_algebra +C-Name: setsearch +Prototype: lGGD0,L, +Help: setsearch(S,x,{flag=0}): determines whether x belongs to the set (or + sorted list) S. + If flag is 0 or omitted, returns 0 if it does not, otherwise returns the index + j such that x==S[j]. If flag is nonzero, return 0 if x belongs to S, + otherwise the index j where it should be inserted. +Doc: determines whether $x$ belongs to the set or sorted list $S$ + (see \kbd{setisset}). + + We first describe the default behavior, when $\fl$ is zero or omitted. If $x$ + belongs to the set $S$, returns the index $j$ such that $S[j]=x$, otherwise + returns 0. + \bprog + ? T = [7,2,3,5]; S = Set(T); + ? setsearch(S, 2) + %2 = 1 + ? setsearch(S, 4) \\ not found + %3 = 0 + ? setsearch(T, 7) \\ search in a randomly sorted vector + %4 = 0 \\ WRONG ! + @eprog\noindent + If $S$ is not a set, we also allow sorted lists with + respect to the \tet{cmp} sorting function, without repeated entries, + as per \tet{listsort}$(L,1)$; otherwise the result is undefined. + \bprog + ? L = List([1,4,2,3,2]); setsearch(L, 4) + %1 = 0 \\ WRONG ! + ? listsort(L, 1); L \\ sort L first + %2 = List([1, 2, 3, 4]) + ? setsearch(L, 4) + %3 = 4 \\ now correct + @eprog\noindent + If $\fl$ is nonzero, this function returns the index $j$ where $x$ should be + inserted, and $0$ if it already belongs to $S$. This is meant to be used for + dynamically growing (sorted) lists, in conjunction with \kbd{listinsert}. + \bprog + ? L = List([1,5,2,3,2]); listsort(L,1); L + %1 = List([1,2,3,5]) + ? j = setsearch(L, 4, 1) \\ 4 should have been inserted at index j + %2 = 4 + ? listinsert(L, 4, j); L + %3 = List([1, 2, 3, 4, 5]) + @eprog + +Function: setunion +Class: basic +Section: linear_algebra +C-Name: setunion +Prototype: GG +Help: setunion(x,y): union of the sets x and y. +Description: + (vec, vec):vec setunion($1, $2) +Doc: union of the two sets $x$ and $y$ (see \kbd{setisset}). + If $x$ or $y$ is not a set, the result is undefined. + +Function: shift +Class: basic +Section: operators +C-Name: gshift +Prototype: GL +Help: shift(x,n): shift x left n bits if n>=0, right -n bits if + n<0. +Doc: shifts $x$ componentwise left by $n$ bits if $n\ge0$ and right by $|n|$ + bits if $n<0$. May be abbreviated as $x$ \kbd{<<} $n$ or $x$ \kbd{>>} $(-n)$. + A left shift by $n$ corresponds to multiplication by $2^{n}$. A right shift + of an integer $x$ by $|n|$ corresponds to a Euclidean division of $x$ by + $2^{|n|}$ with a remainder of the same sign as $x$, hence is not the same (in + general) as $x \kbd{\bs} 2^{n}$. + +Function: shiftmul +Class: basic +Section: operators +C-Name: gmul2n +Prototype: GL +Help: shiftmul(x,n): multiply x by 2^n (n>=0 or n<0). +Doc: multiplies $x$ by $2^{n}$. The difference with + \kbd{shift} is that when $n<0$, ordinary division takes place, hence for + example if $x$ is an integer the result may be a fraction, while for shifts + Euclidean division takes place when $n<0$ hence if $x$ is an integer the result + is still an integer. + +Function: sigma +Class: basic +Section: number_theoretical +C-Name: sumdivk +Prototype: GD1,L, +Help: sigma(x,{k=1}): sum of the k-th powers of the divisors of x. k is + optional and if omitted is assumed to be equal to 1. +Description: + (gen, ?1):int sumdiv($1) + (gen, 0):int numdiv($1) +Doc: sum of the $k^{\text{th}}$ powers of the positive divisors of $|x|$. $x$ + and $k$ must be of type integer. +Variant: Also available is \fun{GEN}{sumdiv}{GEN n}, for $k = 1$. + +Function: sign +Class: basic +Section: operators +C-Name: gsigne +Prototype: iG +Help: sign(x): sign of x, of type integer, real or fraction. +Description: + (mp):small signe($1) + (gen):small gsigne($1) +Doc: \idx{sign} ($0$, $1$ or $-1$) of $x$, which must be of + type integer, real or fraction; \typ{QUAD} with positive discriminants and + \typ{INFINITY} are also supported. + +Function: simplify +Class: basic +Section: conversions +C-Name: simplify +Prototype: G +Help: simplify(x): simplify the object x as much as possible. +Doc: + this function simplifies $x$ as much as it can. Specifically, a complex or + quadratic number whose imaginary part is the integer 0 (i.e.~not \kbd{Mod(0,2)} + or \kbd{0.E-28}) is converted to its real part, and a polynomial of degree $0$ + is converted to its constant term. Simplifications occur recursively. + + This function is especially useful before using arithmetic functions, + which expect integer arguments: + \bprog + ? x = 2 + y - y + %1 = 2 + ? isprime(x) + *** at top-level: isprime(x) + *** ^---------- + *** isprime: not an integer argument in an arithmetic function + ? type(x) + %2 = "t_POL" + ? type(simplify(x)) + %3 = "t_INT" + @eprog + Note that GP results are simplified as above before they are stored in the + history. (Unless you disable automatic simplification with \b{y}, that is.) + In particular + \bprog + ? type(%1) + %4 = "t_INT" + @eprog + +Function: sin +Class: basic +Section: transcendental +C-Name: gsin +Prototype: Gp +Help: sin(x): sine of x. +Description: + (real):real mpsin($1) + (mp):real:prec gsin($1, $prec) + (gen):gen:prec gsin($1, $prec) +Doc: sine of $x$. + Note that, for real $x$, cosine and sine can be obtained simultaneously as + \bprog + cs(x) = my(z = exp(I*x)); [real(z), imag(z)]; + @eprog and for general complex $x$ as + \bprog + cs2(x) = my(z = exp(I*x), u = 1/z); [(z+u)/2, (z-u)/2]; + @eprog Note that the latter function suffers from catastrophic cancellation + when $z^{2} \approx \pm1$. + +Function: sinc +Class: basic +Section: transcendental +C-Name: gsinc +Prototype: Gp +Help: sinc(x): sinc function of x. +Description: + (mp):real:prec gsinc($1, $prec) + (gen):gen:prec gsinc($1, $prec) +Doc: cardinal sine of $x$, i.e. $\sin(x)/x$ if $x\neq 0$, $1$ otherwise. + Note that this function also allows to compute + $$(1-\cos(x)) / x^{2} = \kbd{sinc}(x/2)^{2} / 2$$ + accurately near $x = 0$. + +Function: sinh +Class: basic +Section: transcendental +C-Name: gsinh +Prototype: Gp +Help: sinh(x): hyperbolic sine of x. +Description: + (mp):real:prec gsinh($1, $prec) + (gen):gen:prec gsinh($1, $prec) +Doc: hyperbolic sine of $x$. + +Function: sizebyte +Class: basic +Section: conversions +C-Name: gsizebyte +Prototype: lG +Help: sizebyte(x): number of bytes occupied by the complete tree of the + object x. +Doc: outputs the total number of bytes occupied by the tree representing the + PARI object $x$. +Variant: Also available is \fun{long}{gsizeword}{GEN x} returning a + number of \emph{words}. + +Function: sizedigit +Class: basic +Section: conversions +C-Name: sizedigit +Prototype: lG +Obsolete: 2015-01-13 +Help: sizedigit(x): rough upper bound for the number of decimal digits + of (the components of) x. DEPRECATED. +Doc: + This function is DEPRECATED, essentially meaningless, and provided for + backwards compatibility only. Don't use it! + + outputs a quick upper bound for the number of decimal digits of (the + components of) $x$, off by at most $1$. More precisely, for a positive + integer $x$, it computes (approximately) the ceiling of + $$\kbd{floor}(1 + \log_{2} x) \log_{10}2,$$ + + To count the number of decimal digits of a positive integer $x$, use + \kbd{\#digits(x)}. To estimate (recursively) the size of $x$, use + \kbd{normlp(x)}. + +Function: snfrank +Class: basic +Section: linear_algebra +C-Name: snfrank +Prototype: lGDG +Help: snfrank(D,{q=0}): assuming that D is a Smith normal form + (i.e. vector of elementary divisors) for some module and q a power of an + irreducible element or 0 (default if omitted), returns the rank of D/qD. +Doc: assuming that $D$ is a Smith normal form + (i.e. vector of elementary divisors) for some module and $q$ a power of an + irreducible element or $0$, returns the minimal number of generators for + $D/qD$. For instance, if $q=p^{n}$ where $p$ is a prime number, this is the + dimension of $(p^{n-1}D)/p^{n}D$ as an $\F_{p}$-vector space. An argument $q = 0$ + may be omitted. + + \bprog + ? snfrank([4,4,2], 2) + %1 = 3 + ? snfrank([4,4,2], 4) + %2 = 2 + ? snfrank([4,4,2], 8) + %3 = 0 + ? snfrank([4,4,2]) \\ or snfrank([4,4,2], 0) + %4 = 3 + @eprog\noindent The function also works for $K[x]$-modules: + \bprog + ? D=matsnf([-x-5,-1,-1,0; 0,x^2+10*x+26,-1,-x-5; 1,-x-5,-x-5,1; -1,0,0,1]); + ? snfrank(D, x^2 + 10*x + 27) + %6 = 2 + ? A=matdiagonal([x-1,x^2+1,x-1,(x^2+1)^2,x,(x-1)^2]); D=matsnf(A); + ? snfrank(D,x-1) + %8 = 3 + ? snfrank(D,(x-1)^2) + %9 = 1 + ? snfrank(D,(x-1)^3) + %9 = 0 + ? snfrank(D,x^2+1) + %10 = 2 + @eprog\noindent Finally this function supports any output from \kbd{matsnf} + (e.g., with transformation matrices included, with or without cleanup). + +Function: solve +Class: basic +Section: sums +C-Name: zbrent0 +Prototype: V=GGEp +Help: solve(X=a,b,expr): real root of expression expr (X between a and b), + where either a or b is infinite or expr(a)*expr(b)<=0. +Wrapper: (,,G) +Description: + (gen,gen,gen):gen:prec zbrent(${3 cookie}, ${3 wrapper}, $1, $2, $prec) +Doc: find a real root of expression + \var{expr} between $a$ and $b$. + If both $a$ and $b$ are finite, the condition is that + $\var{expr}(X=a) * \var{expr}(X=b) \le 0$. (You will get an error message + \kbd{roots must be bracketed in solve} if this does not hold.) + + If only one between $a$ and $b$ is finite, say $a$, then $b=\pm\infty$. The + routine will test all $b=a\pm 2^{r}$, with $r\geq \log_{2}(|a|)$ until it finds + a bracket for the root which satisfies the abovementioned condition. + + If both $a$ and $b$ are infinite, the routine will test $0$ and all + $\pm 2^{r}$, $r\geq 0$, until it finds a bracket for the root which + satisfies the condition. + + This routine uses Brent's method and can fail miserably if \var{expr} is + not defined in the whole of $[a,b]$ (try \kbd{solve(x=1, 2, tan(x))}). + + \synt{zbrent}{void *E,GEN (*eval)(void*,GEN),GEN a,GEN b,long prec}. + +Function: solvestep +Class: basic +Section: sums +C-Name: solvestep0 +Prototype: V=GGGED0,L,p +Help: solvestep(X=a,b,step,expr,{flag=0}): find zeros of a function in the real + interval [a,b] by naive interval splitting. +Wrapper: (,,,G) +Description: + (gen,gen,gen,gen,?small):gen:prec solvestep(${4 cookie}, ${4 wrapper}, $1, $2, $3, $5, $prec) +Doc: find zeros of a continuous function in the real interval $[a,b]$ by naive + interval splitting. This function is heuristic and may or may not find the + intended zeros. Binary digits of \fl\ mean + + \item 1: return as soon as one zero is found, otherwise return all + zeros found; + + \item 2: refine the splitting until at least one zero is found + (may loop indefinitely if there are no zeros); + + \item 4: do a multiplicative search (we must have $a > 0$ and $\var{step} > + 1$), otherwise an additive search; \var{step} is the multiplicative or + additive step. + + \item 8: refine the splitting until at least one zero is very close to an + integer. + + \bprog + ? solvestep(X=0,10,1,sin(X^2),1) + %1 = 1.7724538509055160272981674833411451828 + ? solvestep(X=1,12,2,besselj(4,X),4) + %2 = [7.588342434..., 11.064709488...] + @eprog\noindent + + \synt{solvestep}{void *E, GEN (*eval)(void*,GEN), GEN a,GEN b, GEN step,long flag,long prec}. + +Function: sqr +Class: basic +Section: transcendental +C-Name: gsqr +Prototype: G +Help: sqr(x): square of x. NOT identical to x*x. +Description: + (usmall):int sqru($1) + (small):int sqrs($1) + (int):int sqri($1) + (mp):mp gsqr($1) + (gen):gen gsqr($1) +Doc: square of $x$. This operation is not completely + straightforward, i.e.~identical to $x * x$, since it can usually be + computed more efficiently (roughly one-half of the elementary + multiplications can be saved). Also, squaring a $2$-adic number increases + its precision. For example, + \bprog + ? (1 + O(2^4))^2 + %1 = 1 + O(2^5) + ? (1 + O(2^4)) * (1 + O(2^4)) + %2 = 1 + O(2^4) + @eprog\noindent + Note that this function is also called whenever one multiplies two objects + which are known to be \emph{identical}, e.g.~they are the value of the same + variable, or we are computing a power. + \bprog + ? x = (1 + O(2^4)); x * x + %3 = 1 + O(2^5) + ? (1 + O(2^4))^4 + %4 = 1 + O(2^6) + @eprog\noindent + (note the difference between \kbd{\%2} and \kbd{\%3} above). + +Function: sqrt +Class: basic +Section: transcendental +C-Name: gsqrt +Prototype: Gp +Help: sqrt(x): square root of x. +Description: + (real):gen sqrtr($1) + (gen):gen:prec gsqrt($1, $prec) +Doc: principal branch of the square root of $x$, defined as $\sqrt{x} = + \exp(\log x / 2)$. In particular, we have + $\text{Arg}(\text{sqrt}(x))\in{} ]-\pi/2, \pi/2]$, and if $x\in \R$ and $x<0$, + then the result is complex with positive imaginary part. + + Intmod a prime $p$, \typ{PADIC} and \typ{FFELT} are allowed as arguments. In + the first 2 cases (\typ{INTMOD}, \typ{PADIC}), the square root (if it + exists) which is returned is the one whose first $p$-adic digit is in the + interval $[0,p/2]$. For other arguments, the result is undefined. +Variant: For a \typ{PADIC} $x$, the function + \fun{GEN}{Qp_sqrt}{GEN x} is also available. + +Function: sqrtint +Class: basic +Section: number_theoretical +C-Name: sqrtint0 +Prototype: GD& +Help: sqrtint(x,{&r}): integer square root y of x, where x is a nonnegative + real number. If r is present, set it to the remainder x - y^2. +Description: + (gen):int sqrtint($1) +Doc: returns the integer square root of $x$, i.e. the largest integer $y$ + such that $y^{2} \leq x$, where $x$ a nonnegative real number. If $r$ is + present, + set it to the remainder $r = x - y^{2}$, which satisfies $0\leq r < 2y + 1$. + Further, when $x$ is an integer, $r$ is an integer satisfying + $0 \leq r \leq 2y$. + \bprog + ? x = 120938191237; sqrtint(x) + %1 = 347761 + ? sqrt(x) + %2 = 347761.68741970412747602130964414095216 + ? y = sqrtint(x, &r); r + %3 = 478116 + ? x - y^2 + %4 = 478116 + ? sqrtint(9/4, &r) \\ not 3/2 ! + %5 = 1 + ? r + %6 = 5/4 + @eprog +Variant: Also available is \fun{GEN}{sqrtint}{GEN a}. + +Function: sqrtn +Class: basic +Section: transcendental +C-Name: gsqrtn +Prototype: GGD&p +Help: sqrtn(x,n,{&z}): nth-root of x, n must be integer. If present, z is + set to a suitable root of unity to recover all solutions. If it was not + possible, z is set to zero. +Doc: principal branch of the $n$th root of $x$, + i.e.~such that $\text{Arg}(\text{sqrtn}(x))\in{} ]-\pi/n, \pi/n]$. Intmod + a prime and $p$-adics are allowed as arguments. + + If $z$ is present, it is set to a suitable root of unity allowing to + recover all the other roots. If it was not possible, z is + set to zero. In the case this argument is present and no $n$th root exist, + $0$ is returned instead of raising an error. + \bprog + ? sqrtn(Mod(2,7), 2) + %1 = Mod(3, 7) + ? sqrtn(Mod(2,7), 2, &z); z + %2 = Mod(6, 7) + ? sqrtn(Mod(2,7), 3) + *** at top-level: sqrtn(Mod(2,7),3) + *** ^----------------- + *** sqrtn: nth-root does not exist in gsqrtn. + ? sqrtn(Mod(2,7), 3, &z) + %2 = 0 + ? z + %3 = 0 + @eprog + + The following script computes all roots in all possible cases: + \bprog + sqrtnall(x,n)= + { my(V,r,z,r2); + r = sqrtn(x,n, &z); + if (!z, error("Impossible case in sqrtn")); + if (type(x) == "t_INTMOD" || type(x)=="t_PADIC", + r2 = r*z; n = 1; + while (r2!=r, r2*=z;n++)); + V = vector(n); V[1] = r; + for(i=2, n, V[i] = V[i-1]*z); + V + } + addhelp(sqrtnall,"sqrtnall(x,n):compute the vector of nth-roots of x"); + @eprog\noindent +Variant: If $x$ is a \typ{PADIC}, the function + \fun{GEN}{Qp_sqrtn}{GEN x, GEN n, GEN *z} is also available. + +Function: sqrtnint +Class: basic +Section: number_theoretical +C-Name: sqrtnint +Prototype: GL +Help: sqrtnint(x,n): integer n-th root of x, where x is nonnegative real + number. +Description: + (gen,small):int sqrtnint($1, $2) +Doc: returns the integer $n$-th root of $x$, i.e. the largest integer $y$ such + that $y^{n} \leq x$, where $x$ is a nonnegative real number. + \bprog + ? N = 120938191237; sqrtnint(N, 5) + %1 = 164 + ? N^(1/5) + %2 = 164.63140849829660842958614676939677391 + ? sqrtnint(Pi^2, 3) + %3 = 2 + @eprog\noindent The special case $n = 2$ is \tet{sqrtint} + +Function: stirling +Class: basic +Section: combinatorics +C-Name: stirling +Prototype: LLD1,L, +Help: stirling(n,k,{flag=1}): if flag=1 (default) return the Stirling number + of the first kind s(n,k), if flag=2, return the Stirling number of the second + kind S(n,k). +Doc: \idx{Stirling number} of the first kind $s(n,k)$ ($\fl=1$, default) or + of the second kind $S(n,k)$ ($\fl=2$), where $n$, $k$ are nonnegative + integers. The former is $(-1)^{n-k}$ times the + number of permutations of $n$ symbols with exactly $k$ cycles; the latter is + the number of ways of partitioning a set of $n$ elements into $k$ nonempty + subsets. Note that if all $s(n,k)$ are needed, it is much faster to compute + $$\sum_{k} s(n,k) x^{k} = x(x-1)\dots(x-n+1).$$ + Similarly, if a large number of $S(n,k)$ are needed for the same $k$, + one should use + $$\sum_{n} S(n,k) x^{n} = \dfrac{x^{k}}{(1-x)\dots(1-kx)}.$$ + (Should be implemented using a divide and conquer product.) Here are + simple variants for $n$ fixed: + \bprog + /* list of s(n,k), k = 1..n */ + vecstirling(n) = Vec( factorback(vector(n-1,i,1-i*'x)) ) + + /* list of S(n,k), k = 1..n */ + vecstirling2(n) = + { my(Q = x^(n-1), t); + vector(n, i, t = divrem(Q, x-i); Q=t[1]; simplify(t[2])); + } + + /* Bell numbers, B_n = B[n+1] = sum(k = 0, n, S(n,k)), n = 0..N */ + vecbell(N)= + { my (B = vector(N+1)); + B[1] = B[2] = 1; + for (n = 2, N, + my (C = binomial(n-1)); + B[n+1] = sum(k = 1, n, C[k]*B[k]); + ); B; + } + @eprog +Variant: Also available are \fun{GEN}{stirling1}{ulong n, ulong k} + ($\fl=1$) and \fun{GEN}{stirling2}{ulong n, ulong k} ($\fl=2$). + +Function: strchr +Class: basic +Section: programming/specific +C-Name: pari_strchr +Prototype: G +Help: strchr(x): converts integer or vector of integers x to a string, + translating each integer into a character using ASCII encoding. +Doc: converts integer or vector of integers $x$ to a string, translating each + integer (in the range $[1,255]$) into a character using ASCII encoding. + \bprog + ? strchr(97) + %1 = "a" + ? Vecsmall("hello world") + %2 = Vecsmall([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]) + ? strchr(%) + %3 = "hello world" + @eprog + +Function: strexpand +Class: basic +Section: programming/specific +C-Name: strexpand +Prototype: s* +Help: strexpand({x}*): concatenates its (string) arguments into a single + string, performing tilde expansion. +Doc: + converts its argument list into a + single character string (type \typ{STR}, the empty string if $x$ is omitted). + Then perform \idx{environment expansion}, see \secref{se:envir}. + This feature can be used to read \idx{environment variable} values. + \bprog + ? strexpand("$HOME/doc") + %1 = "/home/pari/doc" + + ? module = "aprcl"; n = 10; + ? strexpand("$HOME/doc/", module, n, ".tex") + %3 = "/home/pari/doc/aprcl10.tex" + @eprog + + The individual arguments are read in string context, see \secref{se:strings}. + +Function: strjoin +Class: basic +Section: programming/specific +C-Name: strjoin +Prototype: GDG +Help: strjoin(v,{p = ""}): joins the strings in vector v, separating them with + delimiter p. +Doc: joins the strings in vector $v$, separating them with delimiter $p$. + The reverse operation is \kbd{strsplit}. + \bprog + ? v = ["abc", "def", "ghi"] + ? strjoin(v, "/") + %2 = "abc/def/ghi" + ? strjoin(v) + %3 = "abcdefghi" + @eprog + +Function: strprintf +Class: basic +Section: programming/specific +C-Name: strprintf +Prototype: ss* +Help: strprintf(fmt,{x}*): returns a string built from the remaining + arguments according to the format fmt. +Doc: returns a string built from the remaining arguments according to the + format fmt. The format consists of ordinary characters (not \%), printed + unchanged, and conversions specifications. See \kbd{printf}. + \bprog + ? dir = "/home/pari"; file = "aprcl"; n = 10; + ? strprintf("%s/%s%ld.tex", dir, file, n) + %2 = "/home/pari/aprcl10.tex" + @eprog +Variant: + The variadic version \fun{char *}{pari_sprintf}{const char *fmt, ...} is usually preferable. + +Function: strsplit +Class: basic +Section: programming/specific +C-Name: strsplit +Prototype: GDG +Help: strsplit(s,{p = ""}): splits the string s into a vector of strings, with + p acting as a delimiter between successive fields; if p is empty or omitted, + split into characters. +Doc: splits the string $s$ into a vector of strings, with $p$ acting as a + delimiter. If $p$ is empty or omitted, split the string into characters. + \bprog + ? strsplit("abc::def::ghi", "::") + %1 = ["abc", "def", "ghi"] + ? strsplit("abc", "") + %2 = ["a", "b", "c"] + ? strsplit("aba", "a") + @eprog\noindent If $s$ starts (resp.~ends) with the pattern $p$, then the + first (resp.~last) entry in the vector is the empty string: + \bprog + ? strsplit("aba", "a") + %3 = ["", "b", ""] + @eprog + +Function: strtex +Class: basic +Section: programming/specific +C-Name: strtex +Prototype: s* +Help: strtex({x}*): translates its (string) arguments to TeX format and + returns the resulting string. +Doc: + translates its arguments to TeX format, and concatenates the results into a + single character string (type \typ{STR}, the empty string if $x$ is omitted). + + The individual arguments are read in string context, see \secref{se:strings}. + \bprog + ? v = [1, 2, 3] + %1 [1, 2, 3] + ? strtex(v) + %2 = "\\pmatrix{ 1&2&3\\cr}\n" + @eprog + + \misctitle{\TeX-nical notes} The TeX output engine was originally written + for plain TeX and designed for maximal portability. Unfortunately later + \kbd{LaTeX} packages have obsoleted valid \TeX\ primitives, leading us + to replace TeX's \kbd{\bs{}over} by LaTeX's \kbd{\bs{}frac} in PARI's TeX + output. We have decided not to update further our TeX markup and let the + users of various LaTeX engines customize their preambles. The following + documents the precise changes you may need to include in your style files to + incorporate PARI TeX output verbatim: + + \item if you enabled bit 4 in \tet{TeXstyle} default, you must define + \kbd{\bs{}PARIbreak}; see \kbd{??TeXstyle}; + + \item if you use plain TeX only: you must define \kbd{\bs{}frac} as follows + \bprog + \def\frac#1#2{{#1\over#2}} + @eprog + + \item if you use LaTeX and \kbd{amsmath}, \kbd{\bs{}pmatrix} is + obsoleted in favor of the \kbd{pmatrix} environment; see + \kbd{examples/parigp.sty} for how to re-enable the deprecated construct. + +Function: strtime +Class: basic +Section: programming/specific +C-Name: strtime +Prototype: L +Help: strtime(t): return a string describing the time t in milliseconds, + in the format used by the GP timer. +Doc: + return a string describing the time t in milliseconds in the format used by + the GP timer. + \bprog + ? print(strtime(12345678)) + 3h, 25min, 45,678 ms + ? { + my(t=getabstime()); + F=factor(2^256+1);t=getabstime()-t; + print("factor(2^256+1) took ",strtime(t)); + } + factor(2^256+1) took 1,320 ms + @eprog + +Function: subcyclohminus +Class: basic +Section: number_fields +C-Name: subcyclohminus +Prototype: GDG +Help: subcyclohminus(fH,{p=0}): + Let F be the abelian number field contained in Q(zeta_f) corresponding + to the subgroup H of (Z/fZ)^*. Let h be the relative class number + h^-(F) and Q the Hasse unit index in {1,2}. If Q could be computed, returns + [h, Q]; else returns [2h/Q, 0]. +Doc: Let $F$ be the abelian number field contained in $\Q(\zeta_{f})$ + corresponding to the subgroup $H$ of $(\Z/f\Z)^{*}$. + Computes the relative class number $h^{-}(F)=h(F)/h(F^{+})$ of $F$. + The argument \kbd{fH} encodes $F$ and the data $[f,H]$ as follows: + + \item $\kbd{fH} = [f, H]$, where $H$ is given by a vector of + integral generators, + + \item $\kbd{fH} = [\var{bnr}, H]$, where \var{bnr} is attached to + $\Cl_{f}(\Q)$ and $H$ is a congruence subgroup, + + \item $\kbd{fH} = [G, H]$, where $G$ is \kbd{idealstar}$(f,1)$, and $H$ is + a subgroup of $(\Z/f\Z)^{\times}$, + + \item $\kbd{fH} = f$, where we assume that $H = \{1\}$, i.e., $F = + \Q(\zeta_{f})$, + + \item an irreducible integral polynomial defining a primitive element for $F$. + + The algorithm is based on an analytic class number formula: + $$h^{-}(F)=Q(F)w(F)\prod_{K\subset F}N_{\Q(\zeta_{d})/\Q} + \Bigl(-B_{1,\chi}/2\Bigr)\;,$$ + where $Q(F)$ is the unit index of $F$, $w(F)$ is the number of roots of unity + contained in $F$ and $K$ runs through all imaginary cyclic subfields of $F$. + For each $K$, $d$ is the degree $[K:\Q]$, $\chi$ is an arbitrary injective + character of $G(K/\Q)$ to $\C^{\times}$ and the Bernoulli number is given by + $$B_{1,\chi}=(1/f_{\chi})\sum_{a=1}^{f_{\chi}}a\chi(a)= + -(1/(2-\overline{\chi}(2)) \sum_{1\leq a\leq f_{\chi}/2}\chi(a)\;,$$ + where $f_{\chi}$ is the conductor of $\chi$, namely the conductor of $K$. + The unit index $Q\in\{1,2\}$ is difficult to determine in general. If it + could be computed, the function returns $[a, b] = [h^{-}, Q]$; else + it returns $[2h^{-}/Q, 0]$. More precisely, the second component is $0$ unless + we are in one of the following cases: + + \item If $f=p^{a}$ with a prime number $p$, then $Q=1$. + + \item If $F=\Q(\zeta_{f})$, then $Q=1$ if and only if $f=p^{a}$. + + \item If $f=4p^{a}$ or $p^{a}q^{b}$ with odd prime numbers $p,\,q$, + then $Q=1$ if and only if $[\Q(\zeta_{f}):F]$ is even. + + Finally, the optional parameter $p$ is an \emph{odd} prime number. + If $p$ is given, then \kbd{subcyclohminus} outputs the valuation at $p$ of + $h^{-}(F)$, in other words the maximal integer $e$ such that + $p^{e}\,|\,h^{-}(F)$ by evaluating $p$-adic valuations of Bernoulli numbers. + Since $p$ is odd and $Q\in \{1,2\}$, the latter can be disregarded and + the result is the same as \kbd{valuation(subcyclohminus(f,H)[1], p)}, but + adding this argument $p$ can be much faster when $p$ does not divide $[F:\Q]$ + or if a high power of $p$ divides $[F:\Q]$. + \bprog + ? [a,b] = subcyclohminus(22220); b + %1 = 2 \\ = Q + ? sizedigit(a) + %2 = 4306 \\ huge... + ? valuation(a, 101) + %3 = 41 + ? subcyclohminus(22220, 101) \\ directly compute the valuation + %4 = 41 + @eprog\noindent + shows that $101^{41}$ divides $h^{-}(\Q(\zeta_{22220}))$ exactly. + Let $k_{n}$ be the $n$-th layer of the cyclotomic $\Z_{3}$-extension of + $k=\Q(\sqrt{-1501391})$; the following computes $e_{n}$ for $1 \leq n \leq 3$, + where $3^{e_{n}}$ is the $3$-part of the relative class number $h^{-}(k_{n})$: + \bprog + ? d = 1501391; + ? subcyclohminus([9*d, [28,10,8]], 3) + %1 = 5 + ? subcyclohminus([27*d, [28,188,53]], 3) + %2 = 12 + ? subcyclohminus([81*d, [161,80,242]], 3) + %3 = 26 + @eprog\noindent Note that $h^{+}(k_{n})$ is prime to $3$ for all $n\geq 0$. + + The following example computes the $3$-part of $h^{-}(F)$, where $F$ is + the subfield of the $7860079$-th cyclotomic field with degree $2\cdot 3^{8}$. + \bprog + ? p=7860079; a=znprimroot(p)^(2*3^8); + ? valuation(subcyclohminus([p,a])[1], 3) + time = 1min, 47,896 ms. + %2 = 65 + ? subcyclohminus([p,a], 3) + time = 1,290 ms. + %3 = 65 + @eprog\noindent + +Function: subcycloiwasawa +Class: basic +Section: number_fields +C-Name: subcycloiwasawa +Prototype: GGD0,L, +Help: subcycloiwasawa(fH,p,{n=0}): Let F be the abelian + number field contained in Q(zeta_f) corresponding to the subgroup H of + (Z/fZ)^*. Returns the minus part of Iwasawa polynomials attached to the + cyclotomic Z_p extension of F. +Doc: Let $F$ be the abelian number field contained in $\Q(\zeta_{f})$ + corresponding to the subgroup $H$ of $(\Z/f\Z)^{*}$, let $p > 2$ be an odd + prime not dividing $[F:\Q]$, let $F_{\infty}$ be the cyclotomic + $\Z_{p}$-extension of $F$ and let $F_{n}$ by its $n$-th layer. + Computes the minus part of Iwasawa polynomials and + $\lambda$-invariants attached to $F_{\infty}$, using the Stickelberger + elements $\xi_{n}^{\chi}$ belonging to $F_{n}$. + + The function is only implemented when $p$, $n$ and $f$ are relatively small: + all of $p^{4}$, $p^{n+1}$ and $f$ must fit into an \kbd{unsigned long} integer. + The argument \kbd{fH} encodes the data $[f,H]$ as follows: + + \item $\kbd{fH} = [f, H]$, where $H$ is given by a vector of + integral generators, + + \item $\kbd{fH} = [\var{bnr}, H]$, where \var{bnr} is attached to + $\Cl_{f}(\Q)$ and $H$ is a congruence subgroup, + + \item $\kbd{fH} = [G, H]$, where $G$ is \kbd{idealstar}$(f,1)$, and $H$ is + a subgroup of $(\Z/f\Z)^{\times}$, + + \item $\kbd{fH} = f$, where we assume that $H = \{1\}$, i.e., $F = + \Q(\zeta_{f})$, + + \item an irreducible integral polynomial defining a primitive element for $F$. + + \noindent If $F$ is quadratic, we also allow $p = 2$ and more data is + output (see below). + + For a number field $K$, we write $K_{n}$ for the $n$-th layer of the + cyclotomic $\Z_{p}$-extension of $K$. The algorithm considers all cyclic + subfields $K$ of $F$ and all injective odd characters + $\chi:\text{Gal}(K/\Q)\rightarrow\overline{\Q}_{p}^{\times}$. Let + $\Sigma_{n} = + \text{Gal}(K_{n}/K)$, which is cyclic generated by the Frobenius automorphism + $\sigma$; we write $K_{\chi}=\Q_{p}(\chi)$, + ${\cal O}_{\chi}=\Z_{p}[\chi]$ with maximal ideal $\goth{p}$. + The Stickelberger element + $\xi_{n}^{\chi}$ belongs to ${\cal O}_{\chi}[\Sigma_{n}]$; + the polynomial $f_{n}^{\chi}(x)\in{\cal O}_{\chi}[x]$ + is constructed from $\xi_{n}^{\chi}$ by the correspondence + $\sigma \mapsto 1+x$. If $n$ is sufficiently large, then + $\goth{p}$ does not divide $f_{n}^{\chi}(x)$ and the distinguished polynomial + $g_{n}^{\chi}(x)\in{\cal O}_{\chi}[x]$ is uniquely determined by the relation + $f_{n}^{\chi}(x)=u(x)g_{n}^{\chi}(x),\,u(x)\in{\cal O}_{\chi}[x]^{\times}$. + Owing to Iwasawa Main Conjecture proved by Mazur-Wiles, we can define + the Iwasawa polynomial + $g_{\chi}(x)=\lim_{n\rightarrow\infty}g_{n}^{\chi}(x)\in{\cal O}_{\chi}[x]$. + If $r$ is the smallest integer satisfying + $\deg g_{n}^{\chi}\leq p^{r}$, then we have + $$g_{\chi}(x)\equiv g_{n}^{\chi}(x)\pmod{\goth{p}^{n+1-r}}\;.$$ + Applying the norm from $K_{\chi}$ down to $\Q_{p}$, we obtain polynomials + $G_{\chi}(x), G_{n}^{\chi}(x)\in\Z_{p}[x]$ satisfying the congruence + $$G_{\chi}(x)\equiv G_{n}^{\chi}(x)\pmod{p^{n+1-r}}\;.$$ + Note that $\lambda_{p}^{-}(F)=\sum_{K,\chi} \deg G_{\chi}(x)$ is the Iwasawa + $\lambda^{-}$-invariant of $F$, while the $\mu$-invariant $\mu_{p}(F)$ is + known to be zero by the theorem of Ferrero-Washington. + + If $n = 0$, the function returns $[\lambda_{p}^{-}(F)]$ (the vector may contain + further useful components, see below); for positive $n$, it returns + all non-constant $G_{n}^{\chi}(x)\bmod{p^{n+1-r}}$ as $(K,\chi)$ vary. + + \bprog + ? subcycloiwasawa(22220, 41) \\ f = 22220, H = {1} + %1 = [217] + ? P = polcompositum(x^2 - 42853, polcyclo(5))[1]; + ? subcycloiwasawa(P, 5) + %3 = [3] + ? subcycloiwasawa(P, 5, 4) \\ the sum of the degrees is indeed 3 + %4 = [T + 585, T^2 + 405*T] + @eprog + The first example corresponds to $F = \Q(\zeta_{22220})$ and shows, that + $\lambda_{41}^{-}(F) = 217$. The second one builds $F=\Q(\sqrt{42853}, + \zeta_{5})$ then lists the non-constant $G_{4}^{\chi}(x)\bmod{p^{4}}$ + for $p=5$. + Note that in this case all degrees are $\leq 5$ hence $r \leq 1$ and + $n+1-r\geq n$; so the above also gives $G_{\chi}$ modulo $p^{4}$. + + We henceforth restrict to the quadratic case, where more information is + available, and $p = 2$ is now allowed: we write $F = \Q(\sqrt{d})$ + of discriminant $d$ ($\neq 1$) and character $\chi$. + + \misctitle{Algorithm and output for $n = 0$, $F = \Q(\sqrt{d})$} + Currently, only the case $d < 0$ ($F$ quadratic imaginary, + i.e.~$\chi(-1)=-1$) is implemented. + + \item If $p > 2$, the function returns + $[\lambda, \nu, [e_{0},\dots,e_{k}]]$, where $\lambda=\lambda_{p}^{-}(F)$, + $p^{e_{n}}$ denotes the $p$-part of the class number of $F_{n}$ and $e_{n} = + \lambda n + \nu$ for all $n > k$. We use Gold's theorem + (Acta Arith. vol.26 (1974), pp.~21--32, vol.26 (1975), pp.~233--240). + Then as soon as $e_{n} - e_{n-1} < \varphi(p^{n})$ for some $n \geq 1$, we have + $\lambda_{p}(F)=e_{n}-e_{n-1}$; + if $\chi(p)=1$ we can weaken the hypothesis to $e_{n}-e_{n-1}\leq + \varphi(p^{n})$ for some $n\geq 1$ and obtain the same conclusion. + To compute $e_{n} - e_{n-1}$ we use Bernoulli numbers + (\kbd{subcyclohminus}) if + $\chi(p) = 0$ and a much faster algorithm of Gold + (Pacific J. Math. vol.40 (1972), pp.83--88) otherwise. + + \item For $p=2$, we use Kida's formula (Tohoku Math. J. vol. 31 (1979), + pp.~91--96) and only return $[\lambda^{-}]$. + + When $d > 1$, \kbd{subcycloiwasawa} should calculate + $\lambda_{p}(F)=\lambda_{p}^{+}(F)$, which is conjectured to be zero. + But this is not yet implemented. + + \bprog + ? subcycloiwasawa(x^2+11111, 2) + %1 = [5] /*@Ccom $\lambda_{2}(\Q(\sqrt{-11111}))=5$ */ + ? subcycloiwasawa(x^2+11111, 3) + %2 = [1, 0, []] + ? subcycloiwasawa(x^2+11111, 11) + %3 = [0, 0, []] + @eprog\noindent This shows that for $p = 3$, we have $\lambda = 1$, + $\nu = 0$, and $e_{n} = n$ for all $n \geq 0$. + And at $p = 11$, we have $e_{n} = 0$ for all $n \geq 0$. + + \bprog + ? subcycloiwasawa(x^2+1501391, 3) + time = 23 ms. + %4 = [14, -16, [2, 5]] + @eprog\noindent + computes $e_{n}$ by Gold's algorithm for $F=\Q(\sqrt{-1501391})$. + This shows that at $p = 3$, we have $\lambda=14$, $\nu=-16$, then + $e_{0}=2$, $e_{1}=5$, and $e_{n}=14n-16$ for $n\geq 2$. + \bprog + ? subcycloiwasawa(x^2+956238, 3) + time = 141 ms. + %5 = [14, -19, [1, 3]] + @eprog\noindent + computes $e_{n}$ using Bernoulli numbers for $F=\Q(\sqrt{-956238})$. + This shows that $e_{0}=1$, $e_{1}=3$ and $e_{n}=14n-19$ for $n \geq 2$. + + \misctitle{Algorithm and output for $n > 0$; $F = \Q(\sqrt{d})$} + + \item When $d < 0$ and $n\geq 1$, + \kbd{subcycloiwasawa} computes the Stickelberger element + $\xi_{n} = \xi_{n}^{\chi}\in\Z_{p}[\Sigma_{n}]$ and the Iwasawa polynomial + $g(x) = g_{\chi}(x)\in\Z_{p}[x]$ + from the $n$-th layer $F_{n}$ of the cyclotomic $\Z_{p}$-extension of $F$. + Let $q$ be $p$ ($p$ odd) or 4 ($p = 2$) and let + $q_{0}$ be the lcm of $q$ and the discriminant $d$ of $F$, and let + $q_{n}=q_{0}p^{n}$. + Then $\Sigma_{n}=\text{Gal}(\Q_{n}/\Q)=\text{Gal}(F_{n}/F) + =\langle\,s\,\rangle$, + where $s$ is the Frobenius automorphism $(\Q_{n}/\Q,1+q_{0})$ and + $$\xi_{n}=q_{n}^{-1}\sum_{a=1, (a,q_{n})=1}^{q_{n}} + a\chi(a)^{-1}(\Q_{n}/\Q,a)^{-1}$$ + is an element of $\Q[\Sigma_{n}]$. + For $(p,d)=(2,-1),(2,-2),(2,-3), (2,-6),(3,-3)$, + we know that $\lambda_{p}(F)=0$ and there is nothing to do. + For the other cases, it is proved that $(1/2)\xi_{n}\in\Z_{p}[\Sigma_{n}]$. + The polynomial $f_{n}(x)\in\Z_{p}[x]$ is constructed from $(1/2)\xi_{n}$ + by the + correspondence $s\mapsto 1+x$. If $n$ is sufficiently large, then + $p$ does not divide $f_{n}(x)$ and the distinguished polynomial + $g_{n}(x)\in\Z_{p}[x]$ is uniquely determined by the relation + $f_{n}(x)=u(x)g_{n}(x)$, $u(x)\in\Z_{p}[[x]]^{\times}$. The Iwasawa polynomial + $g(x)$ is defined by $g(x)=\lim_{n\rightarrow\infty}g_{n}(x)$; if $r$ is the + smallest integer satisfying $\deg g=\lambda_{p}(F)\leq p^{r}$, then we have + $g(x)\equiv g_{n}(x)\pmod{\,p^{n+1-r}}$ when $p>2$ and modulo $2^{n-r}$ + otherwise. + + \noindent Conjecturally, we have further + + 1. case $q_{0}=p$: $\xi_{n}\in\Z[\Sigma_{n}]$. + + 2. case $d=-1$ and $\chi(p)=-1$: $\xi_{n}\in\Z[\Sigma_{n}]$. + + 3. case $d=-3$ and $\chi(p)=-1$: $(3/2)\xi_{n}\in\Z[\Sigma_{n}]$. + + 4. other cases: $(1/2)\xi_{n}\in\Z[\Sigma_{n}]$. + + \noindent Finally, \kbd{subcycloiwasawa} outputs $[g]$ where + $g$ is $g_{n}(x)\bmod{p^{n+1-r}}$ ($p$ odd) or $\bmod{2^{n-r}}$ ($p = 2$). + + \bprog + ? subcycloiwasawa(x^2+239, 3, 10) + %6 = [x^6 + 18780*x^5 + 14526*x^4 + 18168*x^3 + 3951*x^2 + 1128*x] + @eprog\noindent This is $g(x)\bmod{3^{9}}$. Indeed, $n = 10$, + $\lambda = 6$ (the degree), hence $r = 2$ and $n + 1 - r = 2$. + + \item When $d > 1$ and $n\geq 1$, $\xi_{n}^{*}\in\Q[\Sigma_{n}]$ is + constructed from + $\chi^{*}=\chi^{-1}\omega$, where $\chi$ is the character of + $F=\Q(\sqrt{d}\,)$ + and $\omega$ is the Teichm\"uller character $\bmod{\,q}$. Next we construct + $f_{n}^{*}(x)\in\Z_{p}[x]$ from $(1/2)\xi_{n}^{*}$ by the correspondence + $s^{-1}\mapsto (1+x)(1+q_{0})^{-1}$ and define the distinguished + polynomial $g_{n}^{*}(x)\in\Z_{p}[x]$ using $f_{n}^{*}(x)$. + Then $g^{*}(x)=\lim_{n\rightarrow\infty}g_{n}^{*}(x)$ is the Iwasawa + polynomial, which has a connection with Greenberg conjecture for $F$. + Let $r$ be the smallest integer satisfying $\deg g^{*}\leq p^{r}$, + then we have $g^{*}(x)\equiv g_{n}^{*}(x)\pmod{\,p^{n+1-r}}$ + when $p>2$ and $g^{*}(x)\equiv g_{n}^{*}(x)\pmod{\,2^{n-r}}$ when $p=2$. + Finally, \kbd{subcycloiwasawa} outputs $[g^{*}]$ where + $g^{*}$ is $g_{n}^{*}(x)\bmod{p^{n+1-r}}$ ($p$ odd) or $\bmod{2^{n-r}}$ ($p = 2$). + + \bprog + ? subcycloiwasawa(x^2-13841, 2, 19) + time = 1min, 17,238 ms. + %7 = [x^3 + 30644*x^2 + 126772*x + 44128] + @eprog + \noindent + This is $g^{*}(x)\bmod{\,2^{17}}$ ($r = 2$), the distinguished polynomial + treated in a paper of T. Fukuda, K. Komatsu, M. Ozaki and T. Tsuji + (Funct. Approx. Comment. Math. vol.54.1, pp.~7--17, 2016). + +Function: subcyclopclgp +Class: basic +Section: number_fields +C-Name: subcyclopclgp +Prototype: GGD0,L, +Help: subcyclopclgp(fH,p,{flag=0}): Let F be the abelian + number field contained in Q(zeta_f) corresponding to the subgroup H of + (Z/fZ)^*. Returns the minus part of Iwasawa polynomials attached to the + ideal class group of F. +Doc: Let $F$ be the abelian number field contained in $\Q(\zeta_{f})$ + corresponding to the subgroup $H$ of $(\Z/f\Z)^{*}$, let $p > 2$ be an odd + prime not dividing $[F:\Q]$. Computes the $p$-Sylow subgroup $A_{F}$ of the + ideal class group using an unconditional algorithm of M.~Aoki and T.~Fukuda + (LNCS. vol.4076, pp.56--71, 2006). + + The argument \kbd{fH} encodes the data $[f,H]$ as follows: + + \item $\kbd{fH} = [f, H]$, where $H$ is given by a vector of + integral generators, + + \item $\kbd{fH} = [\var{bnr}, H]$, where \var{bnr} is attached to + $\Cl_{f}(\Q)$ and $H$ is a congruence subgroup, + + \item $\kbd{fH} = [G, H]$, where $G$ is \kbd{idealstar}$(f,1)$, and $H$ is + a subgroup of $(\Z/f\Z)^{\times}$, + + \item $\kbd{fH} = f$, where we assume that $H = \{1\}$, i.e., $F = + \Q(\zeta_{f})$, + + \item an irreducible integral polynomial defining a primitive element for + $F$. + + \noindent The result is a 6-component vector $v$, and components $2$ or $3$ + can be left empty or only partially computed to save time (see \fl\ below): + + $v[1]$ is $p$. + + $v[2]$ contains $[E, [e_{1},\dots,e_{k}]]$ with $E = \sum_{i} e_{i}$, + meaning that + the order of $A_{F}^{+}$ is $p^{E}$ and its cyclic structure is + $\Z/p^{e_{1}}\Z \times \dots \Z/p^{e_{k}}\Z$ + + $v[3]$ similarly describes the order and the structure of $A_{F}^{-}$. + + $v[4]$ contains the structure of $\text{Gal}(F/\Q)$ as a product of cyclic + groups (elementary divisors). + + $v[5]$ is the number of cyclic subfields $K$ of $F$ except for $\Q$. + + $v[6]$ is the number of $\Q_{p}$-conjugacy classes of injective + characters $\chi:\text{Gal}(K/\Q)\rightarrow\overline{\Q}_{p}^{\times}$. + + \noindent A vector of primes $p$ is also accepted and the result is then a + vector of vectors as above, in the same order as the primes. + + The group $A_{F}$ is the direct sum of $A_{F}^{+}$ and $A_{F}^{-}$; + each of $A_{F}^{+}$ and $A_{F}^{-}$ is decomposed into $\chi$-parts + $A_{\chi}$. By default, the function computes only $|A_{F}^{-}|$ + and an upper bound for $|A_{F}^{+}|$ (expected to be equal to $|A_{F}^{+}|$) + separately with different algorithms. This is expected to be fast. + The behavior is controled by the binary digits of \fl: + + 1: if $|A_{F}^{+}|$ or $|A_{F}^{-}|$ is computed, also determines its group + structure and guarantees informations about $A_{F}^{+}$. + This last part is usually costly. + + 2: do not compute quantities related to $A_{F}^{+}$ (the corresponding + $(e_{i})$ in $v[2]$ is replaced with a dummy empty vector). + + 4: do not compute quantities related to $A_{F}^{-}$ (the corresponding + $(e_{i})$ in $v[3]$ is replaced with a dummy empty vector). + + 8: ignores proper subfields of $F$. This is motivated by the following kind + of problems: let $\Q(p^{k})$ be the $k$-th layer of the cyclotomic + $\Z_{p}$-extension of $\Q$ and define + $\Q(n)=\Q(p_{1}^{e_{1}})\cdots\Q(p_{r}^{e_{r}})$ + when $n$ factors as $n=p_{1}^{e_{1}}\cdots p_{r}^{e_{r}}$, + which is a real cyclic + field of degree $n$ satisfying $\Q(n) \subset \Q(m)$ when $n\mid m$. What are + the prime factors of the class number $h(n)$ of $\Q(n)$ ? The new prime + factors of $h(n)$, not occurring in a lower level, will all be present + when using this \fl. + + The other values are technical and only useful when bit 1 (certification and + structure) is set; do not set them unless you run into difficulties with + default parameters. + + 16: when this bit is set, the function tries to save memory, sacrificing + speed; this typically uses half the memory for a slowdown of a factor $2$. + + 32: likely to speed up the algorithm when the rank of $A_{\chi}$ is large and + to create a minor slowdown otherwise. Though the effect is restricted, the + $3$-class group of $\Q(\sqrt{15338}, \zeta_{5})$ is computed 4 times faster + when this bit is set (see below). + + \misctitle{Examples} With default $\fl=0$, the function (quickly) + determines the exact value of $|A_{F}^{-}|$ and a rigorous upper bound of + $|A_{F}^{+}|$ + which is expected to be equal to $|A_{F}^{+}|$; of course, when the upper + bound is $0$, we know for sure that $A_{F}^{+}$ is trivial. + With $\fl=1$ we obtain the + group structure of $A_{F}$ completely and guarantee the informations about + $A_{F}^{+}$ (slow). + + \bprog + ? subcyclopclgp(22220, 101) + time = 113 ms. + %1 = [101, [0, []], [41, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], + [100, 20, 2, 2], 479, 7999] + @eprog\noindent + This computes the 101-part $A_{F}$ of the ideal class group of + $F=\Q(\zeta_{22220})$. + The output says that $A_{F}^{+}=0$, which is rigorous (since trivial), + and $|A_{F}^{-}|=101^{41}$, more precisely $A_{F}^{-}$ is isomorphic to + $(\Z/101\Z)^{41}$ which is also rigorous + (since the description of $A_{F}^{-}$ is always rigorous). The Galois group + $\text{Gal}(F/\Q)$ is $\Z/100\Z\oplus\Z/20\Z\oplus\Z/2\Z\oplus\Z/2\Z$. + The field $F$ has 479 cyclic subfields different from $\Q$ and + there are 7999 $\Q_{101}$-conjugacy classes of injective characters + $\chi:\text{Gal}(K/\Q)\rightarrow\overline{\Q}_{101}^{\times}$. + + \bprog + ? subcyclopclgp(22220, 11) + time = 83 ms. + %2 = [11, [2, [1, 1]], [16, []], [100, 20, 2, 2], 479, 1799] + @eprog\noindent + This computes the 11-part $A_{F}$ for the same $F$. The result says that + $|A_{F}^{+}|=11^{2}$, $A_{F}^{+}$ is isomorphic to $(\Z/11\Z)^{2}$ + which is not rigorous + and is only an upper bound, and $|A_{F}^{-}|=11^{16}$ which is rigorous. The + group structure of $A_{F}^{-}$ is unknown. + + \bprog + ? subcyclopclgp(22220, 11, 1) + time = 185 ms. + %3 = [11, [2, [1, 1]], [16, [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], + [100, 20, 2, 2], 479, 1799] + @eprog\noindent now guarantees that $A_{F}^{+}$ is isomorphic to + $(\Z/11\Z)^{2}$ and determines that $A_{F}^{-}$ is isomorphic to + $\Z/11^{2}\Z\oplus(\Z/11\Z)^{14}$, + at the expense of slightly increasing the running time. + + We now try a much harder example: $F=\Q(\sqrt{36322},\zeta_{5})$, which + we could define using $f = 726440$ and $H = [41, 61, 111, 131]$ (prove it!). + We will use a defining polynomial instead: + \bprog + ? T = polcompositum(x^2-36322, polcyclo(5), 2); + ? subcyclopclgp(T, 5) \\ fast when non rigorous for A^+ + time = 82 ms. + %4 = [5, [1, [1]], [4, []], [4, 2], 5, 7] + \\ try to certify; requires about 2GB of memory + ? subcyclopclgp(T, 5, 1) + *** subcyclopclgp: the PARI stack overflows ! + current stack size: 1000003072 (1907.352 Mbytes) + ? default(parisizemax,"2G"); + ? subcyclopclgp(T, 5, 1) \\ with more memory, we get an answer + time = 36,201 ms. + %6 = [5, [1, [1]], [4, [3, 1]], [4, 2], 5, 7] + \\ trying to reduce memory use does not work (still need 2GB); slower + ? subcyclopclgp(T, 5, 1+16) + time = 39,450 ms. + @eprog\noindent This shows that $A_{F}^{+}$ is isomorphic to $\Z/5\Z$ and + $A_{F}^{-}$ is isomorphic to $\Z/5^{3}\Z\oplus\Z/5\Z$ for $p=5$. For this example, + trying to reduce memory use with $\fl = 1+16$ fails: the computation becomes + slower and still needs 2GB; $\fl = 1+16+32$ is a disaster: it requires about + 8GB and 9 minutes of computation. + + Here's a situation where the technical flags make a difference: + let $F = \Q(\sqrt{15338}, \zeta_{5})$. + \bprog + ? T = polcompositum(x^2-15338, polcyclo(5), 2); + ? subcyclopclgp(T, 3) + time = 123 ms. + %2 = [3, [1, [1]], [4, []], [4, 2], 5, 5] + ? subcyclopclgp(T, 3, 1) \\ requires a stack of 8GB + time = 4min, 47,822 ms. + %3 = [3, [1, [1]], [4, [1, 1, 1, 1]], [4, 2], 5, 5] + ? subcyclopclgp(T, 3, 1+16); + time = 7min, 20,876 ms. \\ works with 5GB, but slower + ? subcyclopclgp(T, 3, 1+32); + time = 1min, 11,424 ms. \\ also works with 5GB, 4 times faster than original + ? subcyclopclgp(T, 3, 1+16+32); + time = 1min, 47,285 ms. \\ now works with 2.5GB + @eprog + + Let $F = \Q(106)$ defined as above; namely, $F$ is the composite field + of $\Q(\sqrt{2})$ and the subfield of $\Q(\zeta_{53^{2}})$ with degree 53. + This time we shall build the compositum using class field theory: + \bprog + ? Q = bnfinit(y); + ? bnr1 = bnrinit(Q, 8); H1 = Mat(2); + ? bnr2 = bnrinit(Q, [53^2, [1]]); H2 = Mat(53); + ? [bnr,H] = bnrcompositum([bnr1, H1], [bnr2, H2]); + ? subcyclopclgp([bnr,H], 107) + time = 10 ms. + %5 = [107, [1, [1]], [0, []], [106], 3, 105] + ? subcyclopclgp([bnr,H], 107, 1) \\ requires 2.5GB + time = 15min, 13,537 ms. + %6 = [107, [1, [1]], [0, []], [106], 3, 105] + @eprog\noindent Both results are identical (and they were expected to be), + but only the second is rigorous. Flag bit 32 has a minor impact in this case + (reduces timings by 20 s.) + +Function: subgrouplist +Class: basic +Section: number_fields +C-Name: subgrouplist0 +Prototype: GDGD0,L, +Help: subgrouplist(cyc,{bound},{flag=0}): cyc being any object which has a + '.cyc' method giving the cyclic components for a finite Abelian group G, + outputs the list of subgroups of G (of index bounded by bound, + if not omitted), given as HNF left divisors of the SNF matrix corresponding + to G. If flag=0 (default) and 'cyc' is a bnr struture output by bnrinit, + gives only the subgroups for which the modulus is the conductor. +Doc: \var{cyc} being a vector of positive integers giving the cyclic + components for a finite Abelian group $G$ (or any object which has a + \kbd{.cyc} method), outputs the list of subgroups of $G$. Subgroups are + given as HNF left divisors of the SNF matrix corresponding to $G$. + + If $\fl=0$ (default) and \var{cyc} is a \var{bnr} structure output by + \kbd{bnrinit}, gives only the subgroups whose modulus is the conductor. + Otherwise, all subgroups are given. + + If \var{bound} is present, and is a positive integer, restrict the output to + subgroups of index less than \var{bound}. If \var{bound} is a vector + containing a single positive integer $B$, then only subgroups of index + exactly equal to $B$ are computed. For instance + \bprog + ? subgrouplist([6,2]) + %1 = [[6, 0; 0, 2], [2, 0; 0, 2], [6, 3; 0, 1], [2, 1; 0, 1], [3, 0; 0, 2], + [1, 0; 0, 2], [6, 0; 0, 1], [2, 0; 0, 1], [3, 0; 0, 1], [1, 0; 0, 1]] + ? subgrouplist([6,2],3) \\@com index less than 3 + %2 = [[2, 1; 0, 1], [1, 0; 0, 2], [2, 0; 0, 1], [3, 0; 0, 1], [1, 0; 0, 1]] + ? subgrouplist([6,2],[3]) \\@com index 3 + %3 = [[3, 0; 0, 1]] + ? bnr = bnrinit(bnfinit(x), [120,[1]], 1); + ? L = subgrouplist(bnr, [8]); + @eprog\noindent + In the last example, $L$ corresponds to the 24 subfields of + $\Q(\zeta_{120})$, of degree $8$ and conductor $120\infty$ (by setting \fl, + we see there are a total of $43$ subgroups of degree $8$). + \bprog + ? vector(#L, i, galoissubcyclo(bnr, L[i])) + @eprog\noindent + will produce their equations. (For a general base field, you would + have to rely on \tet{bnrstark}, or \tet{bnrclassfield}.) + + \misctitle{Warning} This function requires factoring the exponent of $G$. + If you are only interested in subgroups of index $n$ (or dividing $n$), you + may considerably speed up the function by computing the subgroups of + $G/G^{n}$, whose cyclic components are \kbd{apply(x->gcd(n,x), C)} (where + $C$ gives the cyclic components of $G$). If you want the \var{bnr} variant, + now is a good time to use \kbd{bnrinit(,,, n)} as well, to directly compute + the ray class group modulo $n$-th powers. + +Function: subst +Class: basic +Section: polynomials +C-Name: gsubst +Prototype: GnG +Help: subst(x,y,z): in expression x, replace the variable y by the + expression z. +Doc: replace the simple variable $y$ by the argument $z$ in the ``polynomial'' + expression $x$. If $z$ is a vector, return the vector of the evaluated + expressions \kbd{subst(x, y, z[i])}. + + Every type is allowed for $x$, but if it is not a genuine + polynomial (or power series, or rational function), the substitution will be + done as if the scalar components were polynomials of degree zero. In + particular, beware that: + + \bprog + ? subst(1, x, [1,2; 3,4]) + %1 = + [1 0] + + [0 1] + + ? subst(1, x, Mat([0,1])) + *** at top-level: subst(1,x,Mat([0,1]) + *** ^-------------------- + *** subst: forbidden substitution by a non square matrix. + @eprog\noindent + If $x$ is a power series, $z$ must be either a polynomial, a power + series, or a rational function. If $x$ is a vector, + matrix or list, the substitution is applied to each individual entry. + + Use the function \kbd{substvec} to replace several variables at once, + or the function \kbd{substpol} to replace a polynomial expression. + +Function: substpol +Class: basic +Section: polynomials +C-Name: gsubstpol +Prototype: GGG +Help: substpol(x,y,z): in expression x, replace the polynomial y by the + expression z, using remainder decomposition of x. +Doc: replace the ``variable'' $y$ by the argument $z$ in the ``polynomial'' + expression $x$. Every type is allowed for $x$, but the same behavior + as \kbd{subst} above apply. + + The difference with \kbd{subst} is that $y$ is allowed to be any polynomial + here. The substitution is done moding out all components of $x$ + (recursively) by $y - t$, where $t$ is a new free variable of lowest + priority. Then substituting $t$ by $z$ in the resulting expression. For + instance + \bprog + ? substpol(x^4 + x^2 + 1, x^2, y) + %1 = y^2 + y + 1 + ? substpol(x^4 + x^2 + 1, x^3, y) + %2 = x^2 + y*x + 1 + ? substpol(x^4 + x^2 + 1, (x+1)^2, y) + %3 = (-4*y - 6)*x + (y^2 + 3*y - 3) + @eprog +Variant: Further, \fun{GEN}{gdeflate}{GEN T, long v, long d} attempts to + write $T(x)$ in the form $t(x^{d})$, where $x=$\kbd{pol\_x}$(v)$, and returns + \kbd{NULL} if the substitution fails (for instance in the example \kbd{\%2} + above). + +Function: substvec +Class: basic +Section: polynomials +C-Name: gsubstvec +Prototype: GGG +Help: substvec(x,v,w): in expression x, make a best effort to replace the + variables v1,...,vn by the expression w1,...,wn. +Doc: $v$ being a vector of monomials of degree 1 (variables), + $w$ a vector of expressions of the same length, replace in the expression + $x$ all occurrences of $v_{i}$ by $w_{i}$. The substitutions are done + simultaneously; more precisely, the $v_{i}$ are first replaced by new + variables in $x$, then these are replaced by the $w_{i}$: + \bprog + ? substvec([x,y], [x,y], [y,x]) + %1 = [y, x] + ? substvec([x,y], [x,y], [y,x+y]) + %2 = [y, x + y] \\ not [y, 2*y] + @eprog\noindent As in \kbd{subst}, variables may be replaced + by a vector of values, in which case the cartesian product is returned: + \bprog + ? substvec([x,y], [x,y], [[1,2], 3]) + %3 = [[1, 3], [2, 3]] + ? substvec([x,y], [x,y], [[1,2], [3,4]]) + %4 = [[1, 3], [2, 3], [1, 4], [2, 4]] + @eprog + +Function: sum +Class: basic +Section: sums +C-Name: somme +Prototype: V=GGEDG +Help: sum(X=a,b,expr,{x=0}): x plus the sum (X goes from a to b) of + expression expr. +Doc: sum of expression \var{expr}, + initialized at $x$, the formal parameter going from $a$ to $b$. As for + \kbd{prod}, the initialization parameter $x$ may be given to force the type + of the operations being performed. + + \noindent As an extreme example, compare + + \bprog + ? sum(i=1, 10^4, 1/i); \\@com rational number: denominator has $4345$ digits. + time = 236 ms. + ? sum(i=1, 5000, 1/i, 0.) + time = 8 ms. + %2 = 9.787606036044382264178477904 + @eprog + + % \syn{NO} + +Function: sumalt +Class: basic +Section: sums +C-Name: sumalt0 +Prototype: V=GED0,L,p +Help: sumalt(X=a,expr,{flag=0}): Cohen-Villegas-Zagier's acceleration of + alternating series expr, X starting at a. flag is optional, and can be 0: + default, or 1: uses a slightly different method using Zagier's polynomials. +Wrapper: (,G) +Description: + (gen,gen,?0):gen:prec sumalt(${2 cookie}, ${2 wrapper}, $1, $prec) + (gen,gen,1):gen:prec sumalt2(${2 cookie}, ${2 wrapper}, $1, $prec) +Doc: numerical summation of the series \var{expr}, which should be an + \idx{alternating series} $(-1)^{k} a_{k}$, the formal variable $X$ starting at + $a$. Use an algorithm of Cohen, Villegas and Zagier (\emph{Experiment. Math.} + {\bf 9} (2000), no.~1, 3--12). + + If $\fl=0$, assuming that the $a_{k}$ are the moments of a positive + measure on $[0,1]$, the relative error is $O(3+\sqrt8)^{-n}$ after using + $a_{k}$ for $k\leq n$. If \kbd{realprecision} is $p$, we thus set + $n = \log(10)p/\log(3+\sqrt8)\approx 1.3 p$; besides the time needed to + compute the $a_{k}$, $k\leq n$, the algorithm overhead is negligible: time + $O(p^{2})$ and space $O(p)$. + + If $\fl=1$, use a variant with more complicated polynomials, see + \tet{polzagier}. If the $a_{k}$ are the moments of $w(x)dx$ where $w$ + (or only $xw(x^{2})$) is a smooth function extending analytically to the whole + complex plane, convergence is in $O(14.4^{-n})$. If $xw(x^{2})$ extends + analytically to a smaller region, we still have exponential convergence, + with worse constants. Usually faster when the computation of $a_{k}$ is + expensive. If \kbd{realprecision} is $p$, we thus set + $n = \log(10)p/\log(14.4)\approx 0.86 p$; besides the time needed to + compute the $a_{k}$, $k\leq n$, the algorithm overhead is \emph{not} + negligible: time $O(p^{3})$ and space $O(p^{2})$. Thus, even if the analytic + conditions for rigorous use are met, this variant is only worthwile if the + $a_{k}$ are hard to compute, at least $O(p^{2})$ individually on average: + otherwise we gain a small constant factor (1.5, say) in the number of + needed $a_{k}$ at the expense of a large overhead. + + The conditions for rigorous use are hard to check but the routine is best used + heuristically: even divergent alternating series can sometimes be summed by + this method, as well as series which are not exactly alternating (see for + example \secref{se:user_defined}). It should be used to try and guess the + value of an infinite sum. (However, see the example at the end of + \secref{se:userfundef}.) + + If the series already converges geometrically, + \tet{suminf} is often a better choice: + \bprog + ? \p38 + ? sumalt(i = 1, -(-1)^i / i) - log(2) + time = 0 ms. + %1 = 0.E-38 + ? suminf(i = 1, -(-1)^i / i) \\@com Had to hit \kbd{Ctrl-C} + *** at top-level: suminf(i=1,-(-1)^i/i) + *** ^------ + *** suminf: user interrupt after 10min, 20,100 ms. + ? \p1000 + ? sumalt(i = 1, -(-1)^i / i) - log(2) + time = 90 ms. + %2 = 4.459597722 E-1002 + + ? sumalt(i = 0, (-1)^i / i!) - exp(-1) + time = 670 ms. + %3 = -4.03698781490633483156497361352190615794353338591897830587 E-944 + ? suminf(i = 0, (-1)^i / i!) - exp(-1) + time = 110 ms. + %4 = -8.39147638 E-1000 \\ @com faster and more accurate + @eprog + + \synt{sumalt}{void *E, GEN (*eval)(void*,GEN),GEN a,long prec}. Also + available is \tet{sumalt2} with the same arguments ($\fl = 1$). + +Function: sumdedekind +Class: basic +Section: number_theoretical +C-Name: sumdedekind +Prototype: GG +Help: sumdedekind(h,k): Dedekind sum attached to h,k. +Doc: returns the \idx{Dedekind sum} attached to the integers $h$ and $k$, + corresponding to a fast implementation of + \bprog + s(h,k) = sum(n = 1, k-1, (n/k)*(frac(h*n/k) - 1/2)) + @eprog + +Function: sumdigits +Class: basic +Section: number_theoretical +C-Name: sumdigits0 +Prototype: GDG +Help: sumdigits(n,{B=10}): sum of digits in the integer n, when written in + base B. +Doc: sum of digits in the integer $n$, when written in base $B$. + \bprog + ? sumdigits(123456789) + %1 = 45 + ? sumdigits(123456789, 2) + %2 = 16 + ? sumdigits(123456789, -2) + %3 = 15 + @eprog\noindent Note that the sum of bits in $n$ is also returned by + \tet{hammingweight}. This function is much faster than + \kbd{vecsum(digits(n,B))} when $B$ is $10$ or a power of $2$, and only + slightly faster in other cases. +Variant: Also available is \fun{GEN}{sumdigits}{GEN n}, for $B = 10$. + +Function: sumdiv +Class: basic +Section: sums +C-Name: sumdivexpr +Prototype: GVE +Help: sumdiv(n,X,expr): sum of expression expr, X running over the divisors + of n. +Doc: sum of expression \var{expr} over the positive divisors of $n$. + This function is a trivial wrapper essentially equivalent to + \bprog + D = divisors(n); + sum (i = 1, #D, my(X = D[i]); eval(expr)) + @eprog\noindent + If \var{expr} is a multiplicative function, use \tet{sumdivmult}. + %\syn{NO} + +Function: sumdivmult +Class: basic +Section: sums +C-Name: sumdivmultexpr0 +Prototype: GVE +Help: sumdivmult(n,d,expr): sum of multiplicative function expr, + d running over the divisors of n. +Wrapper: (,,G) +Description: + (gen,,gen):gen sumdivmultexpr(${3 cookie}, ${3 wrapper}, $1) +Doc: sum of \emph{multiplicative} expression \var{expr} over the positive + divisors $d$ of $n$. Assume that \var{expr} evaluates to $f(d)$ + where $f$ is multiplicative: $f(1) = 1$ and $f(ab) = f(a)f(b)$ for coprime + $a$ and $b$. + \synt{sumdivmultexpr}{void *E, GEN (*eval)(void*,GEN), GEN d} + +Function: sumeulerrat +Class: basic +Section: sums +C-Name: sumeulerrat +Prototype: GDGD2,L,p +Help: sumeulerrat(F,{s=1},{a=2}): sum from primes p = a to infinity of F(p^s), + where F is a rational function. +Doc: $\sum_{p\ge a}F(p^{s})$, where the sum is taken over prime numbers + and $F$ is a rational function. + \bprog + ? sumeulerrat(1/p^2) + %1 = 0.45224742004106549850654336483224793417 + ? sumeulerrat(1/p, 2) + %2 = 0.45224742004106549850654336483224793417 + @eprog + +Function: sumformal +Class: basic +Section: polynomials +C-Name: sumformal +Prototype: GDn +Help: sumformal(f,{v}): formal sum of f with respect to v, or to the + main variable of f if v is omitted. +Doc: \idx{formal sum} of the polynomial expression $f$ with respect to the + main variable if $v$ is omitted, with respect to the variable $v$ otherwise; + it is assumed that the base ring has characteristic zero. In other words, + considering $f$ as a polynomial function in the variable $v$, + returns $F$, a polynomial in $v$ vanishing at $0$, such that $F(b) - F(a) + = sum_{v = a+1}^{b} f(v)$: + \bprog + ? sumformal(n) \\ 1 + ... + n + %1 = 1/2*n^2 + 1/2*n + ? f(n) = n^3+n^2+1; + ? F = sumformal(f(n)) \\ f(1) + ... + f(n) + %3 = 1/4*n^4 + 5/6*n^3 + 3/4*n^2 + 7/6*n + ? sum(n = 1, 2000, f(n)) == subst(F, n, 2000) + %4 = 1 + ? sum(n = 1001, 2000, f(n)) == subst(F, n, 2000) - subst(F, n, 1000) + %5 = 1 + ? sumformal(x^2 + x*y + y^2, y) + %6 = y*x^2 + (1/2*y^2 + 1/2*y)*x + (1/3*y^3 + 1/2*y^2 + 1/6*y) + ? x^2 * y + x * sumformal(y) + sumformal(y^2) == % + %7 = 1 + @eprog + +Function: suminf +Class: basic +Section: sums +C-Name: suminf0 +Prototype: V=GEb +Help: suminf(X=a,expr): naive summation (X goes from a to infinity) of real or + complex expression expr. +Wrapper: (,G) +Description: + (gen,gen):gen:prec suminf(${2 cookie}, ${2 wrapper}, $1, $prec) +Doc: Naive summation of expression \var{expr}, the formal parameter $X$ + going from $a$ to infinity. The evaluation stops when the relative error of + the expression is less than the default bit precision for 3 consecutive + evaluations. The expressions must evaluate to a complex number. + + If the expression tends slowly to $0$, like $n^{-a}$ for some $a > 1$, + make sure $b = \kbd{realbitprecision}$ is low: indeed, the algorithm will + require $O(2^{b/a})$ function evaluations and we expect only about $b(1-1/a)$ + correct bits in the answer. If the series is alternating, we can expect $b$ + correct bits but the \tet{sumalt} function should be used instead since its + complexity is polynomial in $b$, instead of exponential. More generally, + \kbd{sumpos} should be used if the terms have a constant sign and + \kbd{sumnum} if the function is $C^{\infty}$. + + \bprog + ? \pb25 + realbitprecision = 25 significant bits (7 decimal digits displayed) + ? exponent(suminf(i = 1, (-1)^i / i) + log(2)) + time = 2min, 2,602 ms. + %1 = -29 + ? \pb45 + realbitprecision = 45 significant bits (13 decimal digits displayed) + ? exponent(suminf(i = 1, 1 / i^2) - zeta(2)) + time = 2,186 ms. + %2 = -23 + + \\ alternatives are much faster + ? \pb 10000 + realbitprecision = 10000 significant bits (3010 decimal digits displayed) + ? exponent(sumalt(i = 1, (-1)^i / i) + log(2)) + time = 25 ms. + %3 = -10043 + + ? \pb 4000 + realbitprecision = 4000 significant bits (1204 decimal digits displayed))) + ? exponent(sumpos(i = 1, 1 / i^2) - zeta(2)) + time = 22,593 ms. + %4 = -4030 + + ? exponent(sumnum(i = 1, 1 / i^2) - zeta(2)) + time = 7,032 ms. + %5 = -4031 + + \\ but suminf is perfect for geometrically converging series + ? exponent(suminf(i = 1, 2^-i) - 1) + time = 25 ms. + %6 = -4003 + @eprog + + \synt{suminf}{void *E, GEN (*eval)(void*,GEN), GEN a, long prec}. + +Function: sumnum +Class: basic +Section: sums +C-Name: sumnum0 +Prototype: V=GEDGp +Help: sumnum(n=a,f,{tab}): numerical summation of f(n) from + n = a to +infinity using Euler-MacLaurin summation. Assume that f + corresponds to a series with positive terms and is a C^oo function; a + must be an integer, and tab, if given, is the output of sumnuminit. +Wrapper: (,G) +Description: + (gen,gen,?gen):gen:prec sumnum(${2 cookie}, ${2 wrapper}, $1, $3, $prec) +Doc: Numerical summation of $f(n)$ at high accuracy using Euler-MacLaurin, + the variable $n$ taking values from $a$ to $+\infty$, where $f$ is assumed to + have positive values and is a $C^{\infty}$ function; \kbd{a} must be an integer + and \kbd{tab}, if given, is the output of \kbd{sumnuminit}. The latter + precomputes abscissas and weights, speeding up the computation; it also allows + to specify the behavior at infinity via \kbd{sumnuminit([+oo, asymp])}. + \bprog + ? \p500 + ? z3 = zeta(3); + ? sumpos(n = 1, n^-3) - z3 + time = 2,332 ms. + %2 = 2.438468843 E-501 + ? sumnum(n = 1, n^-3) - z3 \\ here slower than sumpos + time = 2,752 ms. + %3 = 0.E-500 + @eprog + + \misctitle{Complexity} + The function $f$ will be evaluated at $O(D \log D)$ real arguments, + where $D \approx \kbd{realprecision} \cdot \log(10)$. The routine is geared + towards slowly decreasing functions: if $f$ decreases exponentially fast, + then one of \kbd{suminf} or \kbd{sumpos} should be preferred. + If $f$ satisfies the stronger hypotheses required for Monien summation, + i.e. if $f(1/z)$ is holomorphic in a complex neighbourhood of $[0,1]$, + then \tet{sumnummonien} will be faster since it only requires $O(D/\log D)$ + evaluations: + \bprog + ? sumnummonien(n = 1, 1/n^3) - z3 + time = 1,985 ms. + %3 = 0.E-500 + @eprog\noindent The \kbd{tab} argument precomputes technical data + not depending on the expression being summed and valid for a given accuracy, + speeding up immensely later calls: + \bprog + ? tab = sumnuminit(); + time = 2,709 ms. + ? sumnum(n = 1, 1/n^3, tab) - z3 \\ now much faster than sumpos + time = 40 ms. + %5 = 0.E-500 + + ? tabmon = sumnummonieninit(); \\ Monien summation allows precomputations too + time = 1,781 ms. + ? sumnummonien(n = 1, 1/n^3, tabmon) - z3 + time = 2 ms. + %7 = 0.E-500 + @eprog\noindent The speedup due to precomputations becomes less impressive + when the function $f$ is expensive to evaluate, though: + \bprog + ? sumnum(n = 1, lngamma(1+1/n)/n, tab); + time = 14,180 ms. + + ? sumnummonien(n = 1, lngamma(1+1/n)/n, tabmon); \\ fewer evaluations + time = 717 ms. + @eprog + + \misctitle{Behaviour at infinity} + By default, \kbd{sumnum} assumes that \var{expr} decreases slowly at infinity, + but at least like $O(n^{-2})$. If the function decreases like $n^{\alpha}$ + for some $-2 < \alpha < -1$, then it must be indicated via + \bprog + tab = sumnuminit([+oo, alpha]); /* alpha < 0 slow decrease */ + @eprog\noindent otherwise loss of accuracy is expected. + If the functions decreases quickly, like $\exp(-\alpha n)$ for some + $\alpha > 0$, then it must be indicated via + \bprog + tab = sumnuminit([+oo, alpha]); /* alpha > 0 exponential decrease */ + @eprog\noindent otherwise exponent overflow will occur. + \bprog + ? sumnum(n=1,2^-n) + *** at top-level: sumnum(n=1,2^-n) + *** ^---- + *** _^_: overflow in expo(). + ? tab = sumnuminit([+oo,log(2)]); sumnum(n=1,2^-n, tab) + %1 = 1.000[...] + @eprog + + As a shortcut, one can also input + \bprog + sumnum(n = [a, asymp], f) + @eprog\noindent instead of + \bprog + tab = sumnuminit(asymp); + sumnum(n = a, f, tab) + @eprog + + \misctitle{Further examples} + \bprog + ? \p200 + ? sumnum(n = 1, n^(-2)) - zeta(2) \\ accurate, fast + time = 200 ms. + %1 = -2.376364457868949779 E-212 + ? sumpos(n = 1, n^(-2)) - zeta(2) \\ even faster + time = 96 ms. + %2 = 0.E-211 + ? sumpos(n=1,n^(-4/3)) - zeta(4/3) \\ now much slower + time = 13,045 ms. + %3 = -9.980730723049589073 E-210 + ? sumnum(n=1,n^(-4/3)) - zeta(4/3) \\ fast but inaccurate + time = 365 ms. + %4 = -9.85[...]E-85 + ? sumnum(n=[1,-4/3],n^(-4/3)) - zeta(4/3) \\ with decrease rate, now accurate + time = 416 ms. + %5 = -4.134874156691972616 E-210 + + ? tab = sumnuminit([+oo,-4/3]); + time = 196 ms. + ? sumnum(n=1, n^(-4/3), tab) - zeta(4/3) \\ faster with precomputations + time = 216 ms. + %5 = -4.134874156691972616 E-210 + ? sumnum(n=1,-log(n)*n^(-4/3), tab) - zeta'(4/3) + time = 321 ms. + %7 = 7.224147951921607329 E-210 + @eprog + + Note that in the case of slow decrease ($\alpha < 0$), the exact + decrease rate must be indicated, while in the case of exponential decrease, + a rough value will do. In fact, for exponentially decreasing functions, + \kbd{sumnum} is given for completeness and comparison purposes only: one + of \kbd{suminf} or \kbd{sumpos} should always be preferred. + \bprog + ? sumnum(n=[1, 1], 2^-n) \\ pretend we decrease as exp(-n) + time = 240 ms. + %8 = 1.000[...] \\ perfect + ? sumpos(n=1, 2^-n) + %9 = 1.000[...] \\ perfect and instantaneous + @eprog + + \misctitle{Beware cancellation} The function $f(n)$ is evaluated for huge + values of $n$, so beware of cancellation in the evaluation: + \bprog + ? f(n) = 2 - 1/n - 2*n*log(1+1/n); \\ result is O(1/n^2) + ? z = -2 + log(2*Pi) - Euler; + ? sumnummonien(n=1, f(n)) - z + time = 149 ms. + %12 = 0.E-212 \\ perfect + ? sumnum(n=1, f(n)) - z + time = 116 ms. + %13 = -948.216[...] \\ junk + @eprog\noindent As \kbd{sumnum(n=1, print(n))} shows, we evaluate $f(n)$ for + $n > 1e233$ and our implementation of $f$ suffers from massive cancellation + since we are summing two terms of the order of $O(1)$ for a result in + $O(1/n^{2})$. You can either rewrite your sum so that individual terms are + evaluated without cancellation or locally replace $f(n)$ by an accurate + asymptotic expansion: + \bprog + ? F = truncate( f(1/x + O(x^30)) ); + ? sumnum(n=1, if(n > 1e7, subst(F,x,1/n), f(n))) - z + %15 = 1.1 E-212 \\ now perfect + @eprog + + \synt{sumnum}{(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec)} + where an omitted \var{tab} is coded as \kbd{NULL}. + +Function: sumnumap +Class: basic +Section: sums +C-Name: sumnumap0 +Prototype: V=GEDGp +Help: sumnumap(n=a,f,{tab}): numerical summation of f(n) from + n = a to +infinity using Abel-Plana formula. Assume that f is holomorphic + in the right half-plane Re(z) > a; a must be an integer, and tab, if given, + is the output of sumnumapinit. +Wrapper: (,G) +Description: + (gen,gen,?gen):gen:prec sumnumap(${2 cookie}, ${2 wrapper}, $1, $3, $prec) +Doc: Numerical summation of $f(n)$ at high accuracy using Abel-Plana, + the variable $n$ taking values from $a$ to $+\infty$, where $f$ is + holomorphic in the right half-place $\Re(z) > a$; \kbd{a} must be an integer + and \kbd{tab}, if given, is the output of \kbd{sumnumapinit}. The latter + precomputes abscissas and weights, speeding up the computation; it also allows + to specify the behavior at infinity via \kbd{sumnumapinit([+oo, asymp])}. + \bprog + ? \p500 + ? z3 = zeta(3); + ? sumpos(n = 1, n^-3) - z3 + time = 2,332 ms. + %2 = 2.438468843 E-501 + ? sumnumap(n = 1, n^-3) - z3 \\ here slower than sumpos + time = 2,565 ms. + %3 = 0.E-500 + @eprog + + \misctitle{Complexity} + The function $f$ will be evaluated at $O(D \log D)$ real arguments + and $O(D)$ complex arguments, + where $D \approx \kbd{realprecision} \cdot \log(10)$. The routine is geared + towards slowly decreasing functions: if $f$ decreases exponentially fast, + then one of \kbd{suminf} or \kbd{sumpos} should be preferred. + The default algorithm \kbd{sumnum} is usually a little \emph{slower} + than \kbd{sumnumap} but its initialization function \kbd{sumnuminit} + becomes much faster as \kbd{realprecision} increases. + + If $f$ satisfies the stronger hypotheses required for Monien summation, + i.e. if $f(1/z)$ is holomorphic in a complex neighbourhood of $[0,1]$, + then \tet{sumnummonien} will be faster since it only requires $O(D/\log D)$ + evaluations: + \bprog + ? sumnummonien(n = 1, 1/n^3) - z3 + time = 1,128 ms. + %3 = 0.E-500 + @eprog\noindent The \kbd{tab} argument precomputes technical data + not depending on the expression being summed and valid for a given accuracy, + speeding up immensely later calls: + \bprog + ? tab = sumnumapinit(); + time = 2,567 ms. + ? sumnumap(n = 1, 1/n^3, tab) - z3 \\ now much faster than sumpos + time = 39 ms. + %5 = 0.E-500 + + ? tabmon = sumnummonieninit(); \\ Monien summation allows precomputations too + time = 1,125 ms. + ? sumnummonien(n = 1, 1/n^3, tabmon) - z3 + time = 2 ms. + %7 = 0.E-500 + @eprog\noindent The speedup due to precomputations becomes less impressive + when the function $f$ is expensive to evaluate, though: + \bprog + ? sumnumap(n = 1, lngamma(1+1/n)/n, tab); + time = 10,762 ms. + + ? sumnummonien(n = 1, lngamma(1+1/n)/n, tabmon); \\ fewer evaluations + time = 205 ms. + @eprog + + \misctitle{Behaviour at infinity} + By default, \kbd{sumnumap} assumes that \var{expr} decreases slowly at + infinity, but at least like $O(n^{-2})$. If the function decreases + like $n^{\alpha}$ for some $-2 < \alpha < -1$, then it must be indicated via + \bprog + tab = sumnumapinit([+oo, alpha]); /* alpha < 0 slow decrease */ + @eprog\noindent otherwise loss of accuracy is expected. + If the functions decreases quickly, like $\exp(-\alpha n)$ for some + $\alpha > 0$, then it must be indicated via + \bprog + tab = sumnumapinit([+oo, alpha]); /* alpha > 0 exponential decrease */ + @eprog\noindent otherwise exponent overflow will occur. + \bprog + ? sumnumap(n=1,2^-n) + *** at top-level: sumnumap(n=1,2^-n) + *** ^---- + *** _^_: overflow in expo(). + ? tab = sumnumapinit([+oo,log(2)]); sumnumap(n=1,2^-n, tab) + %1 = 1.000[...] + @eprog + + As a shortcut, one can also input + \bprog + sumnumap(n = [a, asymp], f) + @eprog\noindent instead of + \bprog + tab = sumnumapinit(asymp); + sumnumap(n = a, f, tab) + @eprog + + \misctitle{Further examples} + \bprog + ? \p200 + ? sumnumap(n = 1, n^(-2)) - zeta(2) \\ accurate, fast + time = 169 ms. + %1 = -4.752728915737899559 E-212 + ? sumpos(n = 1, n^(-2)) - zeta(2) \\ even faster + time = 79 ms. + %2 = 0.E-211 + ? sumpos(n=1,n^(-4/3)) - zeta(4/3) \\ now much slower + time = 10,518 ms. + %3 = -9.980730723049589073 E-210 + ? sumnumap(n=1,n^(-4/3)) - zeta(4/3) \\ fast but inaccurate + time = 309 ms. + %4 = -2.57[...]E-78 + ? sumnumap(n=[1,-4/3],n^(-4/3)) - zeta(4/3) \\ decrease rate: now accurate + time = 329 ms. + %6 = -5.418110963941205497 E-210 + + ? tab = sumnumapinit([+oo,-4/3]); + time = 160 ms. + ? sumnumap(n=1, n^(-4/3), tab) - zeta(4/3) \\ faster with precomputations + time = 175 ms. + %5 = -5.418110963941205497 E-210 + ? sumnumap(n=1,-log(n)*n^(-4/3), tab) - zeta'(4/3) + time = 258 ms. + %7 = 9.125239518216767153 E-210 + @eprog + + Note that in the case of slow decrease ($\alpha < 0$), the exact + decrease rate must be indicated, while in the case of exponential decrease, + a rough value will do. In fact, for exponentially decreasing functions, + \kbd{sumnumap} is given for completeness and comparison purposes only: one + of \kbd{suminf} or \kbd{sumpos} should always be preferred. + \bprog + ? sumnumap(n=[1, 1], 2^-n) \\ pretend we decrease as exp(-n) + time = 240 ms. + %8 = 1.000[...] \\ perfect + ? sumpos(n=1, 2^-n) + %9 = 1.000[...] \\ perfect and instantaneous + @eprog + + \synt{sumnumap}{(void *E, GEN (*eval)(void*,GEN), GEN a, GEN tab, long prec)} + where an omitted \var{tab} is coded as \kbd{NULL}. + +Function: sumnumapinit +Class: basic +Section: sums +C-Name: sumnumapinit +Prototype: DGp +Help: sumnumapinit({asymp}): initialize tables for Abel-Plana + summation of a series. +Doc: initialize tables for Abel--Plana summation of a series $\sum f(n)$, + where $f$ is holomorphic in a right half-plane. + If given, \kbd{asymp} is of the form $[\kbd{+oo}, \alpha]$, + as in \tet{intnum} and indicates the decrease rate at infinity of functions + to be summed. A positive + $\alpha > 0$ encodes an exponential decrease of type $\exp(-\alpha n)$ and + a negative $-2 < \alpha < -1$ encodes a slow polynomial decrease of type + $n^{\alpha}$. + \bprog + ? \p200 + ? sumnumap(n=1, n^-2); + time = 163 ms. + ? tab = sumnumapinit(); + time = 160 ms. + ? sumnumap(n=1, n^-2, tab); \\ faster + time = 7 ms. + + ? tab = sumnumapinit([+oo, log(2)]); \\ decrease like 2^-n + time = 164 ms. + ? sumnumap(n=1, 2^-n, tab) - 1 + time = 36 ms. + %5 = 3.0127431466707723218 E-282 + + ? tab = sumnumapinit([+oo, -4/3]); \\ decrease like n^(-4/3) + time = 166 ms. + ? sumnumap(n=1, n^(-4/3), tab); + time = 181 ms. + @eprog + +Function: sumnuminit +Class: basic +Section: sums +C-Name: sumnuminit +Prototype: DGp +Help: sumnuminit({asymp}): initialize tables for Euler-MacLaurin delta + summation of a series with positive terms. +Doc: initialize tables for Euler--MacLaurin delta summation of a series with + positive terms. If given, \kbd{asymp} is of the form $[\kbd{+oo}, \alpha]$, + as in \tet{intnum} and indicates the decrease rate at infinity of functions + to be summed. A positive + $\alpha > 0$ encodes an exponential decrease of type $\exp(-\alpha n)$ and + a negative $-2 < \alpha < -1$ encodes a slow polynomial decrease of type + $n^{\alpha}$. + \bprog + ? \p200 + ? sumnum(n=1, n^-2); + time = 200 ms. + ? tab = sumnuminit(); + time = 188 ms. + ? sumnum(n=1, n^-2, tab); \\ faster + time = 8 ms. + + ? tab = sumnuminit([+oo, log(2)]); \\ decrease like 2^-n + time = 200 ms. + ? sumnum(n=1, 2^-n, tab) + time = 44 ms. + + ? tab = sumnuminit([+oo, -4/3]); \\ decrease like n^(-4/3) + time = 200 ms. + ? sumnum(n=1, n^(-4/3), tab); + time = 221 ms. + @eprog + +Function: sumnumlagrange +Class: basic +Section: sums +C-Name: sumnumlagrange0 +Prototype: V=GEDGp +Help: sumnumlagrange(n=a,f,{tab}): numerical summation of f(n) from + n = a to +infinity using Lagrange summation. + a must be an integer, and tab, if given, is the output of sumnumlagrangeinit. +Wrapper: (,Gp) +Description: + (gen,gen,?gen):gen:prec sumnumlagrange(${2 cookie}, ${2 wrapper}, $1, $3, $prec) +Doc: Numerical summation of $f(n)$ from $n=a$ to $+\infty$ using Lagrange + summation; $a$ must be an integer, and the optional argument \kbd{tab} is + the output of \kbd{sumnumlagrangeinit}. By default, the program assumes that + the $N$th remainder has an asymptotic expansion in integral powers of $1/N$. + If not, initialize \kbd{tab} using \kbd{sumnumlagrangeinit(al)}, where + the asymptotic expansion of the remainder is integral powers of $1/N^{al}$; + $al$ can be equal to $1$ (default), $1/2$, $1/3$, or $1/4$, and also + equal to $2$, but in this latter case it is the $N$th remainder minus one + half of the last summand which has an asymptotic expansion in integral + powers of $1/N^{2}$. + \bprog + ? \p1000 + ? z3 = zeta(3); + ? sumpos(n = 1, n^-3) - z3 + time = 4,440 ms. + %2 = -2.08[...] E-1001 + ? sumnumlagrange(n = 1, n^-3) - z3 \\ much faster than sumpos + time = 25 ms. + %3 = 0.E-1001 + ? tab = sumnumlagrangeinit(); + time = 21 ms. + ? sumnumlagrange(n = 1, n^-3, tab) - z3 + time = 2 ms. /* even faster */ + %5 = 0.E-1001 + + ? \p115 + ? tab = sumnumlagrangeinit([1/3,1/3]); + time = 316 ms. + ? sumnumlagrange(n = 1, n^-(7/3), tab) - zeta(7/3) + time = 24 ms. + %7 = 0.E-115 + ? sumnumlagrange(n = 1, n^(-2/3) - 3*(n^(1/3)-(n-1)^(1/3)), tab) - zeta(2/3) + time = 32 ms. + %8 = 1.0151767349262596893 E-115 + @eprog + + \misctitle{Complexity} + The function $f$ is evaluated at $O(D)$ integer arguments, + where $D \approx \kbd{realprecision} \cdot \log(10)$. + + \synt{sumnumlagrange}{(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec)} + where an omitted \var{tab} is coded as \kbd{NULL}. + +Function: sumnumlagrangeinit +Class: basic +Section: sums +C-Name: sumnumlagrangeinit +Prototype: DGDGp +Help: sumnumlagrangeinit({asymp},{c1}): initialize tables for Lagrange + summation of a series. +Doc: initialize tables for Lagrange summation of a series. By + default, assume that the remainder $R(n) = \sum_{m \geq n} f(m)$ + has an asymptotic expansion + $$R(n) = \sum_{m \geq n} f(n) \approx \sum_{i\geq 1} a_{i} / n^{i}$$ + at infinity. The argument \kbd{asymp} allows to specify different + expansions: + + \item a real number $\beta$ means + $$ R(n) = n^{-\beta} \sum_{i\geq 1} a_{i} / n^{i} $$ + + \item a \typ{CLOSURE} $g$ means + $$R(n) = g(n) \sum_{i\geq 1} a_{i} / n^{i}$$ + (The preceding case corresponds to $g(n) = n^{-\beta}$.) + + \item a pair $[\alpha,\beta]$ where $\beta$ is as above and + $\alpha\in \{2, 1, 1/2, 1/3, 1/4\}$. We let $R_{2}(n) = R(n) - f(n)/2$ + and $R_{\alpha}(n) = R(n)$ for $\alpha\neq 2$. Then + $$R_{\alpha}(n) = g(n) \sum_{i\geq 1} a_{i} / n^{i\alpha}$$ + Note that the initialization times increase considerable for the $\alpha$ + is this list ($1/4$ being the slowest). + + The constant $c1$ is technical and computed by the program, but can be set + by the user: the number of interpolation steps will be chosen close to + $c1\cdot B$, where $B$ is the bit accuracy. + + \bprog + ? \p2000 + ? sumnumlagrange(n=1, n^-2); + time = 173 ms. + ? tab = sumnumlagrangeinit(); + time = 172 ms. + ? sumnumlagrange(n=1, n^-2, tab); + time = 4 ms. + + ? \p115 + ? sumnumlagrange(n=1, n^(-4/3)) - zeta(4/3); + %1 = -0.1093[...] \\ junk: expansion in n^(1/3) + time = 84 ms. + ? tab = sumnumlagrangeinit([1/3,0]); \\ alpha = 1/3 + time = 336 ms. + ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) + time = 84 ms. + %3 = 1.0151767349262596893 E-115 \\ now OK + + ? tab = sumnumlagrangeinit(1/3); \\ alpha = 1, beta = 1/3: much faster + time = 3ms + ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) \\ ... but wrong + %5 = -0.273825[...] \\ junk ! + ? tab = sumnumlagrangeinit(-2/3); \\ alpha = 1, beta = -2/3 + time = 3ms + ? sumnumlagrange(n=1, n^(-4/3), tab) - zeta(4/3) + %6 = 2.030353469852519379 E-115 \\ now OK + @eprog\noindent in The final example with $\zeta(4/3)$, the remainder + $R_{1}(n)$ is of the form $n^{-1/3} \sum_{i\geq 0} a_{i} / n^{i}$, i.e. + $n^{2/3} \sum_{i\geq 1} a_{i} / n^{i}$. The explains the wrong result + for $\beta = 1/3$ and the correction with $\beta = -2/3$. + +Function: sumnummonien +Class: basic +Section: sums +C-Name: sumnummonien0 +Prototype: V=GEDGp +Help: sumnummonien(n=a,f,{tab}): numerical summation from + n = a to +infinity using Monien summation. +Wrapper: (,G) +Description: + (gen,gen,?gen):gen:prec sumnummonien(${2 cookie}, ${2 wrapper}, $1, $3, $prec) +Doc: numerical summation $\sum_{n\geq a} f(n)$ at high accuracy, the variable + $n$ taking values from the integer $a$ to $+\infty$ using Monien summation, + which assumes that $f(1/z)$ has a complex analytic continuation in a (complex) + neighbourhood of the segment $[0,1]$. + + The function $f$ is evaluated at $O(D / \log D)$ real arguments, + where $D \approx \kbd{realprecision} \cdot \log(10)$. + By default, assume that $f(n) = O(n^{-2})$ and has a nonzero asymptotic + expansion + $$f(n) = \sum_{i\geq 2} a_{i} n^{-i}$$ + at infinity. To handle more complicated behaviors and allow time-saving + precomputations (for a given \kbd{realprecision}), see \kbd{sumnummonieninit}. + +Function: sumnummonieninit +Class: basic +Section: sums +C-Name: sumnummonieninit +Prototype: DGDGDGp +Help: sumnummonieninit({asymp},{w},{n0 = 1}): initialize tables for Monien summation of a series with positive terms. +Doc: initialize tables for Monien summation of a series $\sum_{n\geq n_{0}} + f(n)$ where $f(1/z)$ has a complex analytic continuation in a (complex) + neighbourhood of the segment $[0,1]$. + + By default, assume that $f(n) = O(n^{-2})$ and has a nonzero asymptotic + expansion + $$f(n) = \sum_{i\geq 2} a_{i} / n^{i}$$ + at infinity. Note that the sum starts at $i = 2$! The argument \kbd{asymp} + allows to specify different expansions: + + \item a real number $\beta > 0$ means + $$f(n) = \sum_{i\geq 1} a_{i} / n^{i + \beta}$$ + (Now the summation starts at $1$.) + + \item a vector $[\alpha,\beta]$ of reals, where we must have $\alpha > 0$ + and $\alpha + \beta > 1$ to ensure convergence, means that + $$f(n) = \sum_{i\geq 1} a_{i} / n^{\alpha i + \beta}$$ + Note that $\kbd{asymp} = [1, \beta]$ is equivalent to + $\kbd{asymp}=\beta$. + + \bprog + ? \p57 + ? s = sumnum(n = 1, sin(1/sqrt(n)) / n); \\ reference point + + ? \p38 + ? sumnummonien(n = 1, sin(1/sqrt(n)) / n) - s + %2 = -0.001[...] \\ completely wrong + + ? t = sumnummonieninit(1/2); \\ f(n) = sum_i 1 / n^(i+1/2) + ? sumnummonien(n = 1, sin(1/sqrt(n)) / n, t) - s + %3 = 0.E-37 \\ now correct + @eprog\noindent (As a matter of fact, in the above summation, the + result given by \kbd{sumnum} at \kbd{\bs p38} is slighly incorrect, + so we had to increase the accuracy to \kbd{\bs p57}.) + + The argument $w$ is used to sum expressions of the form + $$ \sum_{n\geq n_{0}} f(n) w(n),$$ + for varying $f$ \emph{as above}, and fixed weight function $w$, where we + further assume that the auxiliary sums + $$g_{w}(m) = \sum_{n\geq n_{0}} w(n) / n^{\alpha m + \beta} $$ + converge for all $m\geq 1$. Note that for nonnegative integers $k$, + and weight $w(n) = (\log n)^{k}$, the function + $g_{w}(m) = \zeta^{(k)}(\alpha m + \beta)$ has a simple expression; + for general weights, $g_{w}$ is + computed using \kbd{sumnum}. The following variants are available + + \item an integer $k \geq 0$, to code $w(n) = (\log n)^{k}$; + + \item a \typ{CLOSURE} computing the values $w(n)$, where we + assume that $w(n) = O(n^{\epsilon})$ for all $\epsilon > 0$; + + \item a vector $[w, \kbd{fast}]$, where $w$ is a closure as above + and \kbd{fast} is a scalar; + we assume that $w(n) = O(n^{\kbd{fast}+\epsilon})$; note that + $\kbd{w} = [w, 0]$ is equivalent to $\kbd{w} = w$. Note that if + $w$ decreases exponentially, \kbd{suminf} should be used instead. + + The subsequent calls to \kbd{sumnummonien} \emph{must} use the same value + of $n_{0}$ as was used here. + \bprog + ? \p300 + ? sumnummonien(n = 1, n^-2*log(n)) + zeta'(2) + time = 328 ms. + %1 = -1.323[...]E-6 \\ completely wrong, f does not satisfy hypotheses ! + ? tab = sumnummonieninit(, 1); \\ codes w(n) = log(n) + time = 3,993 ms. + ? sumnummonien(n = 1, n^-2, tab) + zeta'(2) + time = 41 ms. + %3 = -5.562684646268003458 E-309 \\ now perfect + + ? tab = sumnummonieninit(, n->log(n)); \\ generic, slower + time = 9,808 ms. + ? sumnummonien(n = 1, n^-2, tab) + zeta'(2) + time = 40 ms. + %5 = -5.562684646268003458 E-309 \\ identical result + @eprog + +Function: sumnumrat +Class: basic +Section: sums +C-Name: sumnumrat +Prototype: GGp +Help: sumnumrat(F,a): sum from n = a to infinity of F(n), where F + is a rational function of degree less than or equal to -2. +Doc: $\sum_{n\geq a}F(n)$, where $F$ is a rational function of degree less + than or equal to $-2$ and where poles of $F$ at integers $\geq a$ are + omitted from the summation. The argument $a$ must be a \typ{INT} + or \kbd{-oo}. + \bprog + ? sumnumrat(1/(x^2+1)^2,0) + %1 = 1.3068369754229086939178621382829073480 + ? sumnumrat(1/x^2, -oo) \\ value at x=0 is discarded + %2 = 3.2898681336964528729448303332920503784 + ? 2*zeta(2) + %3 = 3.2898681336964528729448303332920503784 + @eprog\noindent When $\deg F = -1$, we define + $$\sum_{-\infty}^{\infty} F(n) := \sum_{n\geq 0} (F(n) + F(-1-n)):$$ + \bprog + ? sumnumrat(1/x, -oo) + %4 = 0.E-38 + @eprog + +Function: sumnumsidi +Class: basic +Section: sums +C-Name: sumnumsidi0 +Prototype: V=GED1,L,p +Help: sumnumsidi(n=a,f,{safe=1}): numerical summation of f(n) from + n = a to +infinity using Sidi summation; a must be an integer. + If safe is set to 0, the function is faster but much less robust. +Wrapper: (,Gb) +Description: + (gen,gen,?long):gen:prec sumnumsidi(${2 cookie}, ${2 wrapper}, $1, $3, $prec) +Doc: Numerical summation of $f(n)$ from $n=a$ to $+\infty$ using Sidi + summation; $a$ must be an integer. The optional argument \kbd{safe} + (set by default to $1$) can be set to $0$ for a faster but much less + robust program; this is likely to lose accuracy when the sum is + non-alternating. + \bprog + ? \pb3328 + ? z = zeta(2); + ? exponent(sumnumsidi(n = 1, 1/n^2) - z) + time = 1,507 ms. + %2 = -3261 \\ already loses some decimals + ? exponent(sumnumsidi(n = 1, 1/n^2, 0) - z) + time = 442 ms. \\ unsafe is much faster + %3 = -2108 \\ ... but very wrong + + ? l2 = log(2); + ? exponent(sumnumsidi(n = 1,(-1)^(n-1)/n) - z) + time = 718 ms. + %5 = -3328 \\ not so slow and perfect + ? exponent(sumnumsidi(n = 1,(-1)^(n-1)/n, 0) - z) + time = 504 ms. + %5 = -3328 \\ still perfect in unsafe mode, not so much faster + @eprog + \misctitle{Complexity} If the bitprecision is $b$, we try to achieve an + absolute error less than $2^{-b}$. The function $f$ is evaluated at $O(b)$ + consecutive integer arguments at bit accuracy $1.56 b$ (resp.~$b$) in safe + (resp.~unsafe) mode. + +Function: sumpos +Class: basic +Section: sums +C-Name: sumpos0 +Prototype: V=GED0,L,p +Help: sumpos(X=a,expr,{flag=0}): sum of positive (or negative) series expr, + the formal + variable X starting at a. flag is optional, and can be 0: default, or 1: + uses a slightly different method using Zagier's polynomials. +Wrapper: (,G) +Description: + (gen,gen,?0):gen:prec sumpos(${2 cookie}, ${2 wrapper}, $1, $prec) + (gen,gen,1):gen:prec sumpos2(${2 cookie}, ${2 wrapper}, $1, $prec) +Doc: numerical summation of the series \var{expr}, which must be a series of + terms having the same sign, the formal variable $X$ starting at $a$. The + algorithm uses Van Wijngaarden's trick for converting such a series into + an alternating one, then \tet{sumalt}. For regular functions, the + function \kbd{sumnum} is in general much faster once the initializations + have been made using \kbd{sumnuminit}. Contrary to \kbd{sumnum}, + \kbd{sumpos} allows functions defined only at integers: + \bprog + ? sumnum(n = 0, 1/n!) + *** at top-level: sumnum(n=1,1/n!) + *** ^--- + *** incorrect type in gtos [integer expected] (t_FRAC). + ? sumpos(n = 0, 1/n!) - exp(1) + %2 = -1.0862155548773347717 E-33 + @eprog\noindent On the other hand, when the function accepts general real + numbers, it is usually advantageous to replace $n$ by \kbd{$n$ * 1.0} in the + sumpos call in particular when rational functions are involved: + \bprog + ? \p500 + ? sumpos(n = 0, n^7 / (n^9+n+1)); + time = 6,108 ms. + ? sumpos(n = 0, n *= 1.; n^7 / (n^9+n+1)); + time = 2,788 ms. + ? sumnumrat(n^7 / (n^9+n+1), 0); + time = 4 ms. + @eprog\noindent In the last example, \kbd{sumnumrat} is of course much + faster but it only applies to rational functions. + + The routine is heuristic and assumes that \var{expr} is more or less a + decreasing function of $X$. In particular, the result will be completely + wrong if \var{expr} is 0 too often. We do not check either that all terms + have the same sign: as \tet{sumalt}, this function should be used to + try and guess the value of an infinite sum. + + If $\fl=1$, use \kbd{sumalt}$(,1)$ instead of \kbd{sumalt}$(,0)$, see + \secref{se:sumalt}. Requiring more stringent analytic properties for + rigorous use, but allowing to compute fewer series terms. + + To reach accuracy $10^{-p}$, both algorithms require $O(p^{2})$ space; + furthermore, assuming the terms decrease polynomially (in $O(n^{-C})$), both + need to compute $O(p^{2})$ terms. The \kbd{sumpos}$(,1)$ variant has a smaller + implied constant (roughly 1.5 times smaller). Since the \kbd{sumalt}$(,1)$ + overhead is now small compared to the time needed to compute series terms, + this last variant should be about 1.5 faster. On the other hand, the + achieved accuracy may be much worse: as for \tet{sumalt}, since + conditions for rigorous use are hard to check, the routine is best used + heuristically. + + \synt{sumpos}{void *E, GEN (*eval)(void*,GEN),GEN a,long prec}. Also + available is \tet{sumpos2} with the same arguments ($\fl = 1$). + +Function: system +Class: basic +Section: programming/specific +C-Name: gpsystem +Prototype: ls +Help: system(str): str being a string, execute the system command str. +Doc: \var{str} is a string representing a system command. This command is + executed, its output written to the standard output (this won't get into your + logfile), and control returns to the PARI system. This simply calls the C + \kbd{system} command. Return the shell return value (which is system-dependent). + Beware that UNIX shell convention for boolean is opposite to GP, true is $0$ + and false is non-$0$. + \bprog + ? system("test -d /") \\ test if '/' is a directory (true) + %1 = 0 + ? system("test -f /") \\ test if '/' is a file (false) + %2 = 1 + @eprog + +Function: tan +Class: basic +Section: transcendental +C-Name: gtan +Prototype: Gp +Help: tan(x): tangent of x. +Description: + (mp):real:prec gtan($1, $prec) + (gen):gen:prec gtan($1, $prec) +Doc: tangent of $x$. + +Function: tanh +Class: basic +Section: transcendental +C-Name: gtanh +Prototype: Gp +Help: tanh(x): hyperbolic tangent of x. +Description: + (mp):real:prec gtanh($1, $prec) + (gen):gen:prec gtanh($1, $prec) +Doc: hyperbolic tangent of $x$. + +Function: taylor +Class: basic +Section: polynomials +C-Name: tayl +Prototype: GnDP +Help: taylor(x,t,{d=seriesprecision}): taylor expansion of x with respect to + t, adding O(t^d) to all components of x. +Doc: Taylor expansion around $0$ of $x$ with respect to + the simple variable $t$. $x$ can be of any reasonable type, for example a + rational function. Contrary to \tet{Ser}, which takes the valuation into + account, this function adds $O(t^{d})$ to all components of $x$. + \bprog + ? taylor(x/(1+y), y, 5) + %1 = (y^4 - y^3 + y^2 - y + 1)*x + O(y^5) + ? Ser(x/(1+y), y, 5) + *** at top-level: Ser(x/(1+y),y,5) + *** ^---------------- + *** Ser: main variable must have higher priority in gtoser. + @eprog + +Function: teichmuller +Class: basic +Section: transcendental +C-Name: teichmuller +Prototype: GDG +Help: teichmuller(x,{tab}): Teichmuller character of p-adic number x. If + x = [p,n], return the lifts of all teichmuller(i + O(p^n)) for + i = 1, ..., p-1. Such a vector can be fed back to teichmuller, as the + optional argument tab, to speed up later computations. +Doc: Teichm\"uller character of the $p$-adic number $x$, i.e. the unique + $(p-1)$-th root of unity congruent to $x / p^{v_{p}(x)}$ modulo $p$. + If $x$ is of the form $[p,n]$, for a prime $p$ and integer $n$, + return the lifts to $\Z$ of the images of $i + O(p^{n})$ for + $i = 1, \dots, p-1$, i.e. all roots of $1$ ordered by residue class modulo + $p$. Such a vector can be fed back to \kbd{teichmuller}, as the + optional argument \kbd{tab}, to speed up later computations. + + \bprog + ? z = teichmuller(2 + O(101^5)) + %1 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) + ? z^100 + %2 = 1 + O(101^5) + ? T = teichmuller([101, 5]); + ? teichmuller(2 + O(101^5), T) + %4 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) + @eprog\noindent As a rule of thumb, if more than + $$p \,/\, 2(\log_{2}(p) + \kbd{hammingweight}(p))$$ + values of \kbd{teichmuller} are to be computed, then it is worthwile to + initialize: + \bprog + ? p = 101; n = 100; T = teichmuller([p,n]); \\ instantaneous + ? for(i=1,10^3, vector(p-1, i, teichmuller(i+O(p^n), T))) + time = 60 ms. + ? for(i=1,10^3, vector(p-1, i, teichmuller(i+O(p^n)))) + time = 1,293 ms. + ? 1 + 2*(log(p)/log(2) + hammingweight(p)) + %8 = 22.316[...] + @eprog\noindent Here the precomputation induces a speedup by a factor + $1293/ 60 \approx 21.5$. + + \misctitle{Caveat} + If the accuracy of \kbd{tab} (the argument $n$ above) is lower than the + precision of $x$, the \emph{former} is used, i.e. the cached value is not + refined to higher accuracy. It the accuracy of \kbd{tab} is larger, then + the precision of $x$ is used: + \bprog + ? Tlow = teichmuller([101, 2]); \\ lower accuracy ! + ? teichmuller(2 + O(101^5), Tlow) + %10 = 2 + 83*101 + O(101^5) \\ no longer a root of 1 + + ? Thigh = teichmuller([101, 10]); \\ higher accuracy + ? teichmuller(2 + O(101^5), Thigh) + %12 = 2 + 83*101 + 18*101^2 + 69*101^3 + 62*101^4 + O(101^5) + @eprog +Variant: + Also available are the functions \fun{GEN}{teich}{GEN x} (\kbd{tab} is + \kbd{NULL}) as well as + \fun{GEN}{teichmullerinit}{long p, long n}. + +Function: theta +Class: basic +Section: transcendental +C-Name: theta +Prototype: GGp +Help: theta(q,z): Jacobi sine theta-function. +Doc: Jacobi sine theta-function + $$ \theta_{1}(z, q) = + 2q^{1/4} \sum_{n\geq 0} (-1)^{n} q^{n(n+1)} \sin((2n+1)z).$$ + +Function: thetanullk +Class: basic +Section: transcendental +C-Name: thetanullk +Prototype: GLp +Help: thetanullk(q,k): k-th derivative at z=0 of theta(q,z). +Doc: $k$-th derivative at $z=0$ of $\kbd{theta}(q,z)$. +Variant: + \fun{GEN}{vecthetanullk}{GEN q, long k, long prec} returns the vector + of all $\dfrac{d^{i}\theta}{dz^{i}}(q,0)$ for all odd $i = 1, 3, \dots, 2k-1$. + \fun{GEN}{vecthetanullk_tau}{GEN tau, long k, long prec} returns + \kbd{vecthetanullk\_tau} at $q = \exp(2i\pi \kbd{tau})$. + +Function: thue +Class: basic +Section: polynomials +C-Name: thue +Prototype: GGDG +Help: thue(tnf,a,{sol}): solve the equation P(x,y)=a, where tnf was created + with thueinit(P), and sol, if present, contains the solutions of Norm(x)=a + modulo units in the number field defined by P. If tnf was computed without + assuming GRH (flag 1 in thueinit), the result is unconditional. If tnf is a + polynomial, compute thue(thueinit(P,0), a). +Doc: returns all solutions of the equation + $P(x,y)=a$ in integers $x$ and $y$, where \var{tnf} was created with + $\kbd{thueinit}(P)$. If present, \var{sol} must contain the solutions of + $\Norm(x)=a$ modulo units of positive norm in the number field + defined by $P$ (as computed by \kbd{bnfisintnorm}). If there are infinitely + many solutions, an error is issued. + + It is allowed to input directly the polynomial $P$ instead of a \var{tnf}, + in which case, the function first performs \kbd{thueinit(P,0)}. This is + very wasteful if more than one value of $a$ is required. + + If \var{tnf} was computed without assuming GRH (flag $1$ in \tet{thueinit}), + then the result is unconditional. Otherwise, it depends in principle of the + truth of the GRH, but may still be unconditionally correct in some + favorable cases. The result is conditional on the GRH if + $a\neq \pm 1$ and $P$ has a single irreducible rational factor, whose + attached tentative class number $h$ and regulator $R$ (as computed + assuming the GRH) satisfy + + \item $h > 1$, + + \item $R/0.2 > 1.5$. + + Here's how to solve the Thue equation $x^{13} - 5y^{13} = - 4$: + \bprog + ? tnf = thueinit(x^13 - 5); + ? thue(tnf, -4) + %1 = [[1, 1]] + @eprog\noindent In this case, one checks that \kbd{bnfinit(x\pow13 -5).no} + is $1$. Hence, the only solution is $(x,y) = (1,1)$ and the result is + unconditional. On the other hand: + \bprog + ? P = x^3-2*x^2+3*x-17; tnf = thueinit(P); + ? thue(tnf, -15) + %2 = [[1, 1]] \\ a priori conditional on the GRH. + ? K = bnfinit(P); K.no + %3 = 3 + ? K.reg + %4 = 2.8682185139262873674706034475498755834 + @eprog + This time the result is conditional. All results computed using this + particular \var{tnf} are likewise conditional, \emph{except} for a right-hand + side of $\pm 1$. + The above result is in fact correct, so we did not just disprove the GRH: + \bprog + ? tnf = thueinit(x^3-2*x^2+3*x-17, 1 /*unconditional*/); + ? thue(tnf, -15) + %4 = [[1, 1]] + @eprog + Note that reducible or nonmonic polynomials are allowed: + \bprog + ? tnf = thueinit((2*x+1)^5 * (4*x^3-2*x^2+3*x-17), 1); + ? thue(tnf, 128) + %2 = [[-1, 0], [1, 0]] + @eprog\noindent Reducible polynomials are in fact much easier to handle. + + \misctitle{Note} When $P$ is irreducible without a real root, the default + strategy is to use brute force enumeration in time $|a|^{1/\deg P}$ and + avoid computing a tough \var{bnf} attached to $P$, see \kbd{thueinit}. + Besides reusing a quantity you might need for other purposes, the + default argument \emph{sol} can also be used to use a different strategy + and prove that there are no solutions; of course you need to compute a + \var{bnf} on you own to obtain \emph{sol}. If there \emph{are} solutions + this won't help unless $P$ is quadratic, since the enumeration will be + performed in any case. + +Function: thueinit +Class: basic +Section: polynomials +C-Name: thueinit +Prototype: GD0,L,p +Help: thueinit(P,{flag=0}): initialize the tnf corresponding to P, that will + be used to solve Thue equations P(x,y) = some-integer. If flag is nonzero, + certify the result unconditionally. Otherwise, assume GRH (much faster of + course). +Doc: initializes the \var{tnf} corresponding to $P$, a nonconstant + univariate polynomial with integer coefficients. + The result is meant to be used in conjunction with \tet{thue} to solve Thue + equations $P(X / Y)Y^{\deg P} = a$, where $a$ is an integer. Accordingly, + $P$ must either have at least two distinct irreducible factors over $\Q$, + or have one irreducible factor $T$ with degree $>2$ or two conjugate + complex roots: under these (necessary and sufficient) conditions, the + equation has finitely many integer solutions. + \bprog + ? S = thueinit(t^2+1); + ? thue(S, 5) + %2 = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]] + ? S = thueinit(t+1); + *** at top-level: thueinit(t+1) + *** ^------------- + *** thueinit: domain error in thueinit: P = t + 1 + @eprog\noindent The hardest case is when $\deg P > 2$ and $P$ is irreducible + with at least one real root. The routine then uses Bilu-Hanrot's algorithm. + + If $\fl$ is nonzero, certify results unconditionally. Otherwise, assume + \idx{GRH}, this being much faster of course. In the latter case, the result + may still be unconditionally correct, see \tet{thue}. For instance in most + cases where $P$ is reducible (not a pure power of an irreducible), \emph{or} + conditional computed class groups are trivial \emph{or} the right hand side + is $\pm1$, then results are unconditional. + + \misctitle{Note} The general philosophy is to disprove the existence of large + solutions then to enumerate bounded solutions naively. The implementation + will overflow when there exist huge solutions and the equation has degree + $> 2$ (the quadratic imaginary case is special, since we can stick to + \kbd{bnfisintnorm}, there are no fundamental units): + \bprog + ? thue(t^3+2, 10^30) + *** at top-level: L=thue(t^3+2,10^30) + *** ^----------------- + *** thue: overflow in thue (SmallSols): y <= 80665203789619036028928. + ? thue(x^2+2, 10^30) \\ quadratic case much easier + %1 = [[-1000000000000000, 0], [1000000000000000, 0]] + @eprog + + \misctitle{Note} It is sometimes possible to circumvent the above, and in any + case obtain an important speed-up, if you can write $P = Q(x^{d})$ for some + $d > 1$ and $Q$ still satisfying the \kbd{thueinit} hypotheses. You can then + solve + the equation attached to $Q$ then eliminate all solutions $(x,y)$ such that + either $x$ or $y$ is not a $d$-th power. + \bprog + ? thue(x^4+1, 10^40); \\ stopped after 10 hours + ? filter(L,d) = + my(x,y); [[x,y] | v<-L, ispower(v[1],d,&x)&&ispower(v[2],d,&y)]; + ? L = thue(x^2+1, 10^40); + ? filter(L, 2) + %4 = [[0, 10000000000], [10000000000, 0]] + @eprog\noindent The last 2 commands use less than 20ms. + + \misctitle{Note} When $P$ is irreducible without a real root, the equation + can be solved unconditionnally in time $|a|^{1/\deg P}$. When this + latter quantity is huge and the equation has no solutions, this fact + may still be ascertained via arithmetic conditions but this now implies + solving norm equations, computing a \var{bnf} and possibly assuming the GRH. + When there is no real root, the code does not compute a \var{bnf} + (with certification if $\fl = 1$) if it expects this to be an ``easy'' + computation (because the result would only be used for huge values of $a$). + See \kbd{thue} for a way to compute an expensive \var{bnf} on your own and + still get a result where this default cheap strategy fails. + +Function: trace +Class: basic +Section: linear_algebra +C-Name: gtrace +Prototype: G +Help: trace(x): trace of x. +Doc: this applies to quite general $x$. If $x$ is not a + matrix, it is equal to the sum of $x$ and its conjugate, except for polmods + where it is the trace as an algebraic number. + + For $x$ a square matrix, it is the ordinary trace. If $x$ is a + nonsquare matrix (but not a vector), an error occurs. + +Function: trap +Class: basic +Section: programming/specific +C-Name: trap0 +Prototype: DrDEDE +Obsolete: 2012-01-17 +Help: trap({e},{rec},seq): this function is obsolete, use "iferr". + Try to execute seq, trapping runtime error e (all of them if e omitted); + sequence rec is executed if the error occurs and is the result of the command. +Wrapper: (,_,_) +Description: + (?str,?closure,?closure):gen trap0($1, $2, $3) +Doc: This function is obsolete, use \tet{iferr}, which has a nicer and much + more powerful interface. For compatibility's sake we now describe the + \emph{obsolete} function \tet{trap}. + + This function tries to + evaluate \var{seq}, trapping runtime error $e$, that is effectively preventing + it from aborting computations in the usual way; the recovery sequence + \var{rec} is executed if the error occurs and the evaluation of \var{rec} + becomes the result of the command. If $e$ is omitted, all exceptions are + trapped. See \secref{se:errorrec} for an introduction to error recovery + under \kbd{gp}. + + \bprog + ? \\@com trap division by 0 + ? inv(x) = trap (e_INV, INFINITY, 1/x) + ? inv(2) + %1 = 1/2 + ? inv(0) + %2 = INFINITY + @eprog\noindent + Note that \var{seq} is effectively evaluated up to the point that produced + the error, and the recovery sequence is evaluated starting from that same + context, it does not "undo" whatever happened in the other branch (restore + the evaluation context): + \bprog + ? x = 1; trap (, /* recover: */ x, /* try: */ x = 0; 1/x) + %1 = 0 + @eprog + + \misctitle{Note} The interface is currently not adequate for trapping + individual exceptions. In the current version \vers, the following keywords + are recognized, but the name list will be expanded and changed in the + future (all library mode errors can be trapped: it's a matter of defining + the keywords to \kbd{gp}): + + \kbd{e\_ALARM}: alarm time-out + + \kbd{e\_ARCH}: not available on this architecture or operating system + + \kbd{e\_STACK}: the PARI stack overflows + + \kbd{e\_INV}: impossible inverse + + \kbd{e\_IMPL}: not yet implemented + + \kbd{e\_OVERFLOW}: all forms of arithmetic overflow, including length + or exponent overflow (when a larger value is supplied than the + implementation can handle). + + \kbd{e\_SYNTAX}: syntax error + + \kbd{e\_MISC}: miscellaneous error + + \kbd{e\_TYPE}: wrong type + + \kbd{e\_USER}: user error (from the \kbd{error} function) + +Function: truncate +Class: basic +Section: conversions +C-Name: trunc0 +Prototype: GD& +Help: truncate(x,{&e}): truncation of x; when x is a power series,take away + the O(X^). If e is present, do not take into account loss of integer part + precision, and set e = error estimate in bits. +Description: + (small):small:parens $1 + (int):int:copy:parens $1 + (real):int truncr($1) + (mp):int mptrunc($1) + (mp, &small):int gcvtoi($1, &$2) + (mp, &int):int trunc0($1, &$2) + (gen):gen gtrunc($1) + (gen, &small):gen gcvtoi($1, &$2) + (gen, &int):gen trunc0($1, &$2) +Doc: truncates $x$ and sets $e$ to the number of + error bits. When $x$ is in $\R$, this means that the part after the decimal + point is chopped away, $e$ is the binary exponent of the difference between + the original and the truncated value (the ``fractional part''). If the + exponent of $x$ is too large compared to its precision (i.e.~$e>0$), the + result is undefined and an error occurs if $e$ was not given. The function + applies componentwise on vector / matrices; $e$ is then the maximal number of + error bits. If $x$ is a rational function, the result is the ``integer part'' + (Euclidean quotient of numerator by denominator) and $e$ is not set. + + Note a very special use of \kbd{truncate}: when applied to a power series, it + transforms it into a polynomial or a rational function with denominator + a power of $X$, by chopping away the $O(X^{k})$. Similarly, when applied to + a $p$-adic number, it transforms it into an integer or a rational number + by chopping away the $O(p^{k})$. +Variant: The following functions are also available: \fun{GEN}{gtrunc}{GEN x} + and \fun{GEN}{gcvtoi}{GEN x, long *e}. + +Function: type +Class: basic +Section: programming/specific +C-Name: type0 +Prototype: G +Help: type(x): return the type of the GEN x. +Description: + (gen):typ typ($1) +Doc: this is useful only under \kbd{gp}. Returns the internal type name of + the PARI object $x$ as a string. Check out existing type names with the + metacommand \b{t}. For example \kbd{type(1)} will return "\typ{INT}". +Variant: The macro \kbd{typ} is usually simpler to use since it returns a + \kbd{long} that can easily be matched with the symbols \typ{*}. The name + \kbd{type} was avoided since it is a reserved identifier for some compilers. + +Function: unclone +Class: gp2c +Description: + (small):void (void)0 /*unclone*/ + (gen):void gunclone($1) + +Function: unexport +Class: basic +Section: programming/specific +Help: unexport(x,...,z): remove x,...,z from the list of variables exported to + the parallel world. +Doc: remove $x,\ldots, z$ from the list of variables exported + to the parallel world. See \key{export}. + +Function: unexportall +Class: basic +Section: programming/specific +C-Name: unexportall +Prototype: v +Help: unexportall(): empty the list of variables exported to the parallel + world. +Doc: empty the list of variables exported to the parallel world. + +Function: uninline +Class: basic +Section: programming/specific +Obsolete: 2018-11-27 +Help: uninline(): forget all inline variables. DEPRECATED, use export. +Doc: Exit the scope of all current \kbd{inline} variables. DEPRECATED, use + \kbd{export} / \kbd{unexport}. + +Function: until +Class: basic +Section: programming/control +C-Name: untilpari +Prototype: vEI +Help: until(a,seq): evaluate the expression sequence seq until a is nonzero. +Doc: evaluates \var{seq} until $a$ is not + equal to 0 (i.e.~until $a$ is true). If $a$ is initially not equal to 0, + \var{seq} is evaluated once (more generally, the condition on $a$ is tested + \emph{after} execution of the \var{seq}, not before as in \kbd{while}). + +Function: valuation +Class: basic +Section: conversions +C-Name: gpvaluation +Prototype: GDG +Help: valuation(x,{p}): valuation of x with respect to p. +Doc: + computes the highest + exponent of $p$ dividing $x$. If $p$ is of type integer, $x$ must be an + integer, an intmod whose modulus is divisible by $p$, a fraction, a + $q$-adic number with $q=p$, or a polynomial or power series in which case the + valuation is the minimum of the valuation of the coefficients. + + If $p$ is of type polynomial, $x$ must be of type polynomial or rational + function, and also a power series if $x$ is a monomial. Finally, the + valuation of a vector, complex or quadratic number is the minimum of the + component valuations. + + If $x=0$, the result is \kbd{+oo} if $x$ is an exact object. If $x$ is a + $p$-adic numbers or power series, the result is the exponent of the zero. + Any other type combinations gives an error. + + Finally, $p$ can be omitted if $x$ is a \typ{PADIC} (taken to be the + underlying prime), a \typ{SER} or a \typ{POL} (taken to be the main variable). +Variant: Also available is + \fun{long}{gvaluation}{GEN x, GEN p}, which returns \tet{LONG_MAX} if $x = 0$ + and the valuation as a \kbd{long} integer. + +Function: varhigher +Class: basic +Section: conversions +C-Name: varhigher +Prototype: sDn +Help: varhigher(name,{v}): return a variable 'name' whose priority is + higher than the priority of v (of all existing variables if v is omitted). +Doc: return a variable \emph{name} whose priority is higher + than the priority of $v$ (of all existing variables if $v$ is omitted). + This is a counterpart to \tet{varlower}. + \bprog + ? Pol([x,x], t) + *** at top-level: Pol([x,x],t) + *** ^------------ + *** Pol: incorrect priority in gtopoly: variable x <= t + ? t = varhigher("t", x); + ? Pol([x,x], t) + %3 = x*t + x + @eprog\noindent This routine is useful since new GP variables directly + created by the interpreter always have lower priority than existing + GP variables. When some basic objects already exist in a variable + that is incompatible with some function requirement, you can now + create a new variable with a suitable priority instead of changing variables + in existing objects: + \bprog + ? K = nfinit(x^2+1); + ? rnfequation(K,y^2-2) + *** at top-level: rnfequation(K,y^2-2) + *** ^-------------------- + *** rnfequation: incorrect priority in rnfequation: variable y >= x + ? y = varhigher("y", x); + ? rnfequation(K, y^2-2) + %3 = y^4 - 2*y^2 + 9 + @eprog\noindent + \misctitle{Caution 1} + The \emph{name} is an arbitrary character string, only used for display + purposes and need not be related to the GP variable holding the result, nor + to be a valid variable name. In particular the \emph{name} can + not be used to retrieve the variable, it is not even present in the parser's + hash tables. + \bprog + ? x = varhigher("#"); + ? x^2 + %2 = #^2 + @eprog + \misctitle{Caution 2} There are a limited number of variables and if no + existing variable with the given display name has the requested + priority, the call to \kbd{varhigher} uses up one such slot. Do not create + new variables in this way unless it's absolutely necessary, + reuse existing names instead and choose sensible priority requirements: + if you only need a variable with higher priority than $x$, state so + rather than creating a new variable with highest priority. + \bprog + \\ quickly use up all variables + ? n = 0; while(1,varhigher("tmp"); n++) + *** at top-level: n=0;while(1,varhigher("tmp");n++) + *** ^------------------- + *** varhigher: no more variables available. + *** Break loop: type 'break' to go back to GP prompt + break> n + 65510 + \\ infinite loop: here we reuse the same 'tmp' + ? n = 0; while(1,varhigher("tmp", x); n++) + @eprog + +Function: variable +Class: basic +Section: conversions +C-Name: gpolvar +Prototype: DG +Help: variable({x}): main variable of object x. Gives p for p-adic x, 0 + if no variable can be attached to x. Returns the list of user variables if + x is omitted. +Description: + (pol):var:parens:copy $var:1 + (gen):gen gpolvar($1) +Doc: + gives the main variable of the object $x$ (the variable with the highest + priority used in $x$), and $p$ if $x$ is a $p$-adic number. Return $0$ if + $x$ has no variable attached to it. + \bprog + ? variable(x^2 + y) + %1 = x + ? variable(1 + O(5^2)) + %2 = 5 + ? variable([x,y,z,t]) + %3 = x + ? variable(1) + %4 = 0 + @eprog\noindent The construction + \bprog + if (!variable(x),...) + @eprog\noindent can be used to test whether a variable is attached to $x$. + + If $x$ is omitted, returns the list of user variables known to the + interpreter, by order of decreasing priority. (Highest priority is initially + $x$, which come first until \tet{varhigher} is used.) If \kbd{varhigher} + or \kbd{varlower} are used, it is quite possible to end up with different + variables (with different priorities) printed in the same way: they + will then appear multiple times in the output: + \bprog + ? varhigher("y"); + ? varlower("y"); + ? variable() + %4 = [y, x, y] + @eprog\noindent Using \kbd{v = variable()} then \kbd{v[1]}, \kbd{v[2]}, + etc.~allows to recover and use existing variables. +Variant: However, in library mode, this function should not be used for $x$ + non-\kbd{NULL}, since \tet{gvar} is more appropriate. Instead, for + $x$ a $p$-adic (type \typ{PADIC}), $p$ is $gel(x,2)$; otherwise, use + \fun{long}{gvar}{GEN x} which returns the variable number of $x$ if + it exists, \kbd{NO\_VARIABLE} otherwise, which satisfies the property + $\kbd{varncmp}(\kbd{NO\_VARIABLE}, v) > 0$ for all valid variable number + $v$, i.e. it has lower priority than any variable. + +Function: variables +Class: basic +Section: conversions +C-Name: variables_vec +Prototype: DG +Help: variables({x}): all variables occurring in object x, sorted by + decreasing priority. Returns the list of user variables if x is omitted. +Doc: + returns the list of all variables occurring in object $x$ sorted by + decreasing priority. If $x$ is omitted, return all polynomial variables + known to the interpreter (this will include \kbd{x} and \kbd{y}, + which are always defined on startup); user variables which do + not occur in \typ{POL} or \typ{SER} constructions are \emph{not} included. + To see all user variables, use \b{uv}. + \bprog + ? variables([x^2 + y*z + O(t), a+x]) + %1 = [x, y, z, t, a] + @eprog\noindent The construction + \bprog + if (!variables(x),...) + @eprog\noindent can be used to test whether a variable is attached to $x$. + + If \kbd{varhigher} or \kbd{varlower} are used, it is quite possible to end up + with different variables (having different priorities) printed in the same + way. They will then appear multiple times in the output: + \bprog + ? y1 = varhigher("y"); y2 = varlower("y"); + ? variables(y*y1*y2) + %2 = [y, y, y] + @eprog +Variant: + Also available is \fun{GEN}{variables_vecsmall}{GEN x} which returns + the (sorted) variable numbers instead of the attached monomials of degree 1. + +Function: varlower +Class: basic +Section: conversions +C-Name: varlower +Prototype: sDn +Help: varlower(name,{v}): return a variable 'name' whose priority is lower + than the priority of v (of all existing variables if v is omitted. +Doc: return a variable \emph{name} whose priority is lower + than the priority of $v$ (of all existing variables if $v$ is omitted). + This is a counterpart to \tet{varhigher}. + + New GP variables directly created by the interpreter always + have lower priority than existing GP variables, but it is not easy + to check whether an identifier is currently unused, so that the + corresponding variable has the expected priority when it's created! + Thus, depending on the session history, the same command may fail or succeed: + \bprog + ? t; z; \\ now t > z + ? rnfequation(t^2+1,z^2-t) + *** at top-level: rnfequation(t^2+1,z^ + *** ^-------------------- + *** rnfequation: incorrect priority in rnfequation: variable t >= t + @eprog\noindent Restart and retry: + \bprog + ? z; t; \\ now z > t + ? rnfequation(t^2+1,z^2-t) + %2 = z^4 + 1 + @eprog\noindent It is quite annoying for package authors, when trying to + define a base ring, to notice that the package may fail for some users + depending on their session history. The safe way to do this is as follows: + \bprog + ? z; t; \\ In new session: now z > t + ... + ? t = varlower("t", 'z); + ? rnfequation(t^2+1,z^2-2) + %2 = z^4 - 2*z^2 + 9 + ? variable() + %3 = [x, y, z, t] + @eprog + \bprog + ? t; z; \\ In new session: now t > z + ... + ? t = varlower("t", 'z); \\ create a new variable, still printed "t" + ? rnfequation(t^2+1,z^2-2) + %2 = z^4 - 2*z^2 + 9 + ? variable() + %3 = [x, y, t, z, t] + @eprog\noindent Now both constructions succeed. Note that in the + first case, \kbd{varlower} is essentially a no-op, the existing variable $t$ + has correct priority. While in the second case, two different variables are + displayed as \kbd{t}, one with higher priority than $z$ (created in the first + line) and another one with lower priority (created by \kbd{varlower}). + + \misctitle{Caution 1} + The \emph{name} is an arbitrary character string, only used for display + purposes and need not be related to the GP variable holding the result, nor + to be a valid variable name. In particular the \emph{name} can + not be used to retrieve the variable, it is not even present in the parser's + hash tables. + \bprog + ? x = varlower("#"); + ? x^2 + %2 = #^2 + @eprog + \misctitle{Caution 2} There are a limited number of variables and if no + existing variable with the given display name has the requested + priority, the call to \kbd{varlower} uses up one such slot. Do not create + new variables in this way unless it's absolutely necessary, + reuse existing names instead and choose sensible priority requirements: + if you only need a variable with higher priority than $x$, state so + rather than creating a new variable with highest priority. + \bprog + \\ quickly use up all variables + ? n = 0; while(1,varlower("x"); n++) + *** at top-level: n=0;while(1,varlower("x");n++) + *** ^------------------- + *** varlower: no more variables available. + *** Break loop: type 'break' to go back to GP prompt + break> n + 65510 + \\ infinite loop: here we reuse the same 'tmp' + ? n = 0; while(1,varlower("tmp", x); n++) + @eprog + +Function: vecextract +Class: basic +Section: linear_algebra +C-Name: extract0 +Prototype: GGDG +Help: vecextract(x,y,{z}): extraction of the components of the matrix or + vector x according to y and z. If z is omitted, y represents columns, otherwise + y corresponds to rows and z to columns. y and z can be vectors (of indices), + strings (indicating ranges as in "1..10") or masks (integers whose binary + representation indicates the indices to extract, from left to right 1, 2, 4, + 8, etc.). +Description: + (vec,gen,?gen):vec extract0($1, $2, $3) +Doc: extraction of components of the vector or matrix $x$ according to $y$. + In case $x$ is a matrix, its components are the \emph{columns} of $x$. The + parameter $y$ is a component specifier, which is either an integer, a string + describing a range, or a vector. + + If $y$ is an integer, it is considered as a mask: the binary bits of $y$ are + read from right to left, but correspond to taking the components from left to + right. For example, if $y=13=(1101)_{2}$ then the components 1,3 and 4 are + extracted. + + If $y$ is a vector (\typ{VEC}, \typ{COL} or \typ{VECSMALL}), which must have + integer entries, these entries correspond to the component numbers to be + extracted, in the order specified. + + If $y$ is a string, it can be + + \item a single (nonzero) index giving a component number (a negative + index means we start counting from the end). + + \item a range of the form \kbd{"$a$..$b$"}, where $a$ and $b$ are + indexes as above. Any of $a$ and $b$ can be omitted; in this case, we take + as default values $a = 1$ and $b = -1$, i.e.~ the first and last components + respectively. We then extract all components in the interval $[a,b]$, in + reverse order if $b < a$. + + In addition, if the first character in the string is \kbd{\pow}, the + complement of the given set of indices is taken. + + If $z$ is not omitted, $x$ must be a matrix. $y$ is then the \emph{row} + specifier, and $z$ the \emph{column} specifier, where the component specifier + is as explained above. + + \bprog + ? v = [a, b, c, d, e]; + ? vecextract(v, 5) \\@com mask + %1 = [a, c] + ? vecextract(v, [4, 2, 1]) \\@com component list + %2 = [d, b, a] + ? vecextract(v, "2..4") \\@com interval + %3 = [b, c, d] + ? vecextract(v, "-1..-3") \\@com interval + reverse order + %4 = [e, d, c] + ? vecextract(v, "^2") \\@com complement + %5 = [a, c, d, e] + ? vecextract(matid(3), "2..", "..") + %6 = + [0 1 0] + + [0 0 1] + @eprog + The range notations \kbd{v[i..j]} and \kbd{v[\pow i]} (for \typ{VEC} or + \typ{COL}) and \kbd{M[i..j, k..l]} and friends (for \typ{MAT}) implement a + subset of the above, in a simpler and \emph{faster} way, hence should be + preferred in most common situations. The following features are not + implemented in the range notation: + + \item reverse order, + + \item omitting either $a$ or $b$ in \kbd{$a$..$b$}. + +Function: vecmax +Class: basic +Section: operators +C-Name: vecmax0 +Prototype: GD& +Help: vecmax(x,{&v}): largest entry in the vector/matrix x. If v + is present, set it to the index of a largest entry (indirect max). +Description: + (gen):gen vecmax($1) + (gen, &gen):gen vecmax0($1, &$2) +Doc: if $x$ is a list, vector or matrix, returns the largest entry of $x$, + otherwise returns a copy of $x$. Error if $x$ is empty. Here, largest + refers to the ordinary real ordering (\kbd{<=}). + + If $v$ is given, set it to the index of a largest entry (indirect maximum), + when $x$ is a vector or list. If $x$ is a matrix, set $v$ to coordinates + $[i,j]$ such that $x[i,j]$ is a largest entry. This argument $v$ is + ignored for other types. + When the vector has equal largest entries, the first occurence is + chosen; in a matrix, the smallest $j$ is chosen first, then the smallest $i$. + vector or matrix. + + \bprog + ? vecmax([10, 20, -30, 40]) + %1 = 40 + ? vecmax([10, 20, -30, 40], &v); v + %2 = 4 + ? vecmax([10, 20; -30, 40], &v); v + %3 = [2, 2] + @eprog +Variant: When $v$ is not needed, the function \fun{GEN}{vecmax}{GEN x} is + also available. + +Function: vecmin +Class: basic +Section: operators +C-Name: vecmin0 +Prototype: GD& +Help: vecmin(x,{&v}): smallest entry in the vector/matrix x. If v is + present, set it to the index of a smallest + entry (indirect min). +Description: + (gen):gen vecmin($1) + (gen, &gen):gen vecmin0($1, &$2) +Doc: if $x$ is a list, vector or matrix, returns the smallest entry of $x$, + otherwise returns a copy of $x$. Error if $x$ is empty. Here, smallest + refers to the ordinary real ordering (\kbd{<=}). + + If $v$ is given, set it to the index of a smallest entry (indirect minimum), + when $x$ is a vector or list. If $x$ is a matrix, set $v$ to coordinates + $[i,j]$ such that $x[i,j]$ is a smallest entry. This argument $v$ is + ignored for other types. + When a vector has equal smallest entries, the first occurence is + chosen; in a matrix, the smallest $j$ is chosen first, then the smallest $i$. + + \bprog + ? vecmin([10, 20, -30, 40]) + %1 = -30 + ? vecmin([10, 20, -30, 40], &v); v + %2 = 3 + ? vecmin([10, 20; -30, 40], &v); v + %3 = [2, 1] + ? vecmin([1,0;0,0], &v); v + %3 = [2, 1] + @eprog +Variant: When $v$ is not needed, the function \fun{GEN}{vecmin}{GEN x} is also + available. + +Function: vecprod +Class: basic +Section: linear_algebra +C-Name: vecprod +Prototype: G +Help: vecprod(v): return the product of the components of the vector v. +Doc: return the product of the components of the vector $v$. Return $1$ on an + empty vector. + \bprog + ? vecprod([1,2,3]) + %1 = 6 + ? vecprod([]) + %2 = 1 + @eprog + +Function: vecsearch +Class: basic +Section: linear_algebra +C-Name: vecsearch +Prototype: lGGDG +Help: vecsearch(v,x,{cmpf}): determines whether x belongs to the sorted + vector v. If the comparison function cmpf is explicitly given, assume + that v was sorted according to vecsort(, cmpf). +Doc: determines whether $x$ belongs to the sorted vector or list $v$: return + the (positive) index where $x$ was found, or $0$ if it does not belong to + $v$. + + If the comparison function cmpf is omitted, we assume that $v$ is sorted in + increasing order, according to the standard comparison function \kbd{lex}, + thereby restricting the possible types for $x$ and the elements of $v$ + (integers, fractions, reals, and vectors of such). We also transparently + allow a \typ{VECSMALL} $x$ in this case, for the natural ordering of the + integers. + + If \kbd{cmpf} is present, it is understood as a comparison function and we + assume that $v$ is sorted according to it, see \tet{vecsort} for how to + encode comparison functions. + \bprog + ? v = [1,3,4,5,7]; + ? vecsearch(v, 3) + %2 = 2 + ? vecsearch(v, 6) + %3 = 0 \\ not in the list + ? vecsearch([7,6,5], 5) \\ unsorted vector: result undefined + %4 = 0 + @eprog\noindent Note that if we are sorting with respect to a key + which is expensive to compute (e.g. a discriminant), one should rather + precompute all keys, sort that vector and search in the vector of keys, + rather than searching in the original vector with respect to a comparison + function. + + By abuse of notation, $x$ is also allowed to be a matrix, seen as a vector + of its columns; again by abuse of notation, a \typ{VEC} is considered + as part of the matrix, if its transpose is one of the matrix columns. + \bprog + ? v = vecsort([3,0,2; 1,0,2]) \\ sort matrix columns according to lex order + %1 = + [0 2 3] + + [0 2 1] + ? vecsearch(v, [3,1]~) + %2 = 3 + ? vecsearch(v, [3,1]) \\ can search for x or x~ + %3 = 3 + ? vecsearch(v, [1,2]) + %4 = 0 \\ not in the list + @eprog\noindent + +Function: vecsort +Class: basic +Section: linear_algebra +C-Name: vecsort0 +Prototype: GDGD0,L, +Help: vecsort(x,{cmpf},{flag=0}): sorts the vector x in ascending order, + according to the comparison function cmpf, if not omitted. Binary digits of + flag (if present) mean: 1: indirect sorting, return the permutation instead + of the permuted vector, 4: use descending instead of ascending order, 8: + remove duplicate entries. +Description: + (vecsmall,?gen,?small):vecsmall vecsort0($1, $2, $3) + (vecvecsmall, ,?0):vecvecsmall sort($1) + (vec, , ?0):vec sort($1) + (vec, , 1):vecsmall indexsort($1) + (vec, , 2):vec lexsort($1) + (vec, gen):vec vecsort0($1, $2, 0) + (vec, ?gen, 1):vecsmall vecsort0($1, $2, 1) + (vec, ?gen, 3):vecsmall vecsort0($1, $2, 3) + (vec, ?gen, 5):vecsmall vecsort0($1, $2, 5) + (vec, ?gen, 7):vecsmall vecsort0($1, $2, 7) + (vec, ?gen, 9):vecsmall vecsort0($1, $2, 9) + (vec, ?gen, 11):vecsmall vecsort0($1, $2, 11) + (vec, ?gen, 13):vecsmall vecsort0($1, $2, 13) + (vec, ?gen, 15):vecsmall vecsort0($1, $2, 15) + (vec, ?gen, #small):vec vecsort0($1, $2, $3) + (vec, ?gen, small):gen vecsort0($1, $2, $3) +Doc: sorts the vector $x$ in ascending order, using a mergesort method. + $x$ must be a list, vector or matrix (seen as a vector of its columns). + Note that mergesort is stable, hence the initial ordering of ``equal'' + entries (with respect to the sorting criterion) is not changed. + + If \kbd{cmpf} is omitted, we use the standard comparison function + \kbd{lex}, thereby restricting the possible types for the elements of $x$ + (integers, fractions or reals and vectors of those). We also transparently + allow a \typ{VECSMALL} $x$ in this case, for the standard ordering on the + integers. + + If \kbd{cmpf} is present, it is understood as a comparison function and we + sort according to it. The following possibilities exist: + + \item an integer $k$: sort according to the value of the $k$-th + subcomponents of the components of~$x$. + + \item a vector: sort lexicographically according to the components listed in + the vector. For example, if $\kbd{cmpf}=\kbd{[2,1,3]}$, sort with respect to + the second component, and when these are equal, with respect to the first, + and when these are equal, with respect to the third. + + \item a comparison function: \typ{CLOSURE} with two arguments $x$ and $y$, + and returning a real number which is $<0$, $>0$ or $=0$ if $xy$ or + $x=y$ respectively. + + \item a key: \typ{CLOSURE} with one argument $x$ and returning + the value $f(x)$ with respect to which we sort. + + \bprog + ? vecsort([3,0,2; 1,0,2]) \\ sort columns according to lex order + %1 = + [0 2 3] + + [0 2 1] + ? vecsort(v, (x,y)->y-x) \\@com reverse sort + ? vecsort(v, (x,y)->abs(x)-abs(y)) \\@com sort by increasing absolute value + ? vecsort(v, abs) \\@com sort by increasing absolute value, using key + ? cmpf(x,y) = my(dx = poldisc(x), dy = poldisc(y)); abs(dx) - abs(dy); + ? v = [x^2+1, x^3-2, x^4+5*x+1] vecsort(v, cmpf) \\@com comparison function + ? vecsort(v, x->abs(poldisc(x))) \\@com key + @eprog\noindent + The \kbd{abs} and \kbd{cmpf} examples show how to use a named function + instead of an anonymous function. It is preferable to use a \var{key} + whenever possible rather than include it in the comparison function as above + since the key is evaluated $O(n)$ times instead of $O(n\log n)$, + where $n$ is the number of entries. + + A direct approach is also possible and equivalent to using a sorting key: + \bprog + ? T = [abs(poldisc(x)) | x<-v]; + ? perm = vecsort(T,,1); \\@com indirect sort + ? vecextract(v, perm) + @eprog\noindent This also provides the vector $T$ of all keys, which is + interesting for instance in later \tet{vecsearch} calls: it is more + efficient to sort $T$ (\kbd{T = vecextract(T, perm)}) then search for a key + in $T$ rather than to search in $v$ using a comparison function or a key. + Note also that \tet{mapisdefined} is often easier to use and faster than + \kbd{vecsearch}. + + \noindent The binary digits of \fl\ mean: + + \item 1: indirect sorting of the vector $x$, i.e.~if $x$ is an + $n$-component vector, returns a permutation of $[1,2,\dots,n]$ which + applied to the components of $x$ sorts $x$ in increasing order. + For example, \kbd{vecextract(x, vecsort(x,,1))} is equivalent to + \kbd{vecsort(x)}. + + \item 4: use descending instead of ascending order. + + \item 8: remove ``duplicate'' entries with respect to the sorting function + (keep the first occurring entry). For example: + \bprog + ? vecsort([Pi,Mod(1,2),z], (x,y)->0, 8) \\@com make everything compare equal + %1 = [3.141592653589793238462643383] + ? vecsort([[2,3],[0,1],[0,3]], 2, 8) + %2 = [[0, 1], [2, 3]] + @eprog + +Function: vecsum +Class: basic +Section: linear_algebra +C-Name: vecsum +Prototype: G +Help: vecsum(v): return the sum of the components of the vector v. +Doc: return the sum of the components of the vector $v$. Return $0$ on an + empty vector. + \bprog + ? vecsum([1,2,3]) + %1 = 6 + ? vecsum([]) + %2 = 0 + @eprog + +Function: vector +Class: basic +Section: linear_algebra +C-Name: vecteur +Prototype: GDVDE +Help: vector(n,{X},{expr=0}): row vector with n components of expression + expr (X ranges from 1 to n). By default, fills with 0s. +Doc: creates a row vector (type + \typ{VEC}) with $n$ components whose components are the expression + \var{expr} evaluated at the integer points between 1 and $n$. If the last + two arguments are omitted, fills the vector with zeroes. + \bprog + ? vector(3,i, 5*i) + %1 = [5, 10, 15] + ? vector(3) + %2 = [0, 0, 0] + @eprog + + The variable $X$ is lexically scoped to each evaluation of \var{expr}. Any + change to $X$ within \var{expr} does not affect subsequent evaluations, it + still runs 1 to $n$. A local change allows for example different indexing: + \bprog + vector(10, i, i=i-1; f(i)) \\ i = 0, ..., 9 + vector(10, i, i=2*i; f(i)) \\ i = 2, 4, ..., 20 + @eprog\noindent + This per-element scope for $X$ differs from \kbd{for} loop evaluations, + as the following example shows: + \bprog + n = 3 + v = vector(n); vector(n, i, i++) ----> [2, 3, 4] + v = vector(n); for (i = 1, n, v[i] = i++) ----> [2, 0, 4] + @eprog\noindent + %\syn{NO} + +Function: vectorsmall +Class: basic +Section: linear_algebra +C-Name: vecteursmall +Prototype: GDVDE +Help: vectorsmall(n,{X},{expr=0}): VECSMALL with n components of expression + expr (X ranges from 1 to n) which must be small integers. By default, fills + with 0s. +Doc: creates a row vector of small integers (type \typ{VECSMALL}) with $n$ + components whose components are the expression \var{expr} evaluated at the + integer points between 1 and $n$. + %\syn{NO} + +Function: vectorv +Class: basic +Section: linear_algebra +C-Name: vvecteur +Prototype: GDVDE +Help: vectorv(n,{X},{expr=0}): column vector with n components of expression + expr (X ranges from 1 to n). By default, fill with 0s. +Doc: as \tet{vector}, but returns a column vector (type \typ{COL}). + %\syn{NO} + +Function: version +Class: basic +Section: programming/specific +C-Name: pari_version +Prototype: +Help: version(): returns the PARI version as [major,minor,patch] or [major,minor,patch,GITversion]. +Doc: returns the current version number as a \typ{VEC} with three integer + components (major version number, minor version number and patchlevel); + if your sources were obtained through our version control system, this will + be followed by further more precise arguments, including + e.g.~a~\kbd{git} \emph{commit hash}. + + This function is present in all versions of PARI following releases 2.3.4 + (stable) and 2.4.3 (testing). + + Unless you are working with multiple development versions, you probably only + care about the 3 first numeric components. In any case, the \kbd{lex} function + offers a clever way to check against a particular version number, since it will + compare each successive vector entry, numerically or as strings, and will not + mind if the vectors it compares have different lengths: + \bprog + if (lex(version(), [2,3,5]) >= 0, + \\ code to be executed if we are running 2.3.5 or more recent. + , + \\ compatibility code + ); + @eprog\noindent On a number of different machines, \kbd{version()} could return either of + \bprog + %1 = [2, 3, 4] \\ released version, stable branch + %1 = [2, 4, 3] \\ released version, testing branch + %1 = [2, 6, 1, 15174, ""505ab9b"] \\ development + @eprog + + In particular, if you are only working with released versions, the first + line of the gp introductory message can be emulated by + \bprog + [M,m,p] = version(); + printf("GP/PARI CALCULATOR Version %s.%s.%s", M,m,p); + @eprog\noindent If you \emph{are} working with many development versions of + PARI/GP, the 4th and/or 5th components can be profitably included in the + name of your logfiles, for instance. + + \misctitle{Technical note} For development versions obtained via \kbd{git}, + the 4th and 5th components are liable to change eventually, but we document + their current meaning for completeness. The 4th component counts the number + of reachable commits in the branch (analogous to \kbd{svn}'s revision + number), and the 5th is the \kbd{git} commit hash. In particular, \kbd{lex} + comparison still orders correctly development versions with respect to each + others or to released versions (provided we stay within a given branch, + e.g. \kbd{master})! + +Function: warning +Class: basic +Section: programming/specific +C-Name: warning0 +Prototype: vs* +Help: warning({str}*): display warning message str. +Description: + (gen,...):void pari_warn(warnuser, mkvecn($#, $2)) +Doc: outputs the message ``user warning'' + and the argument list (each of them interpreted as a string). + If colors are enabled, this warning will be in a different color, + making it easy to distinguish. + \bprog + warning(n, " is very large, this might take a while.") + @eprog + +Function: weber +Class: basic +Section: transcendental +C-Name: weber0 +Prototype: GD0,L,p +Help: weber(x,{flag=0}): one of Weber's f function of x. flag is optional, + and can be 0: default, function f(x)=exp(-i*Pi/24)*eta((x+1)/2)/eta(x), + 1: function f1(x)=eta(x/2)/eta(x) + 2: function f2(x)=sqrt(2)*eta(2*x)/eta(x). +Doc: one of Weber's three $f$ functions. + If $\fl=0$, returns + $$f(x)=\exp(-i\pi/24)\cdot\eta((x+1)/2)\,/\,\eta(x) \quad\hbox{such that}\quad + j=(f^{24}-16)^{3}/f^{24}\,,$$ + where $j$ is the elliptic $j$-invariant (see the function \kbd{ellj}). + If $\fl=1$, returns + $$f_{1}(x)=\eta(x/2)\,/\,\eta(x)\quad\hbox{such that}\quad + j=(f_{1}^{24}+16)^{3}/f_{1}^{24}\,.$$ + Finally, if $\fl=2$, returns + $$f_{2}(x)=\sqrt{2}\eta(2x)\,/\,\eta(x)\quad\hbox{such that}\quad + j=(f_{2}^{24}+16)^{3}/f_{2}^{24}.$$ + Note the identities $f^{8}=f_{1}^{8}+f_{2}^{8}$ and $ff_{1}f_{2}=\sqrt2$. +Variant: Also available are \fun{GEN}{weberf}{GEN x, long prec}, + \fun{GEN}{weberf1}{GEN x, long prec} and \fun{GEN}{weberf2}{GEN x, long prec}. + +Function: whatnow +Class: gp +Section: programming/specific +C-Name: whatnow0 +Prototype: vr +Help: whatnow(key): if key was present in GP version 1.39.15, gives + the new function name. +Description: + (str):void whatnow($1, 0) +Doc: if keyword \var{key} is the name of a function that was present in GP + version 1.39.15, outputs the new function name and syntax, if it + changed at all. Functions that where introduced since then, then modified + are also recognized. + \bprog + ? whatnow("mu") + New syntax: mu(n) ===> moebius(n) + + moebius(x): Moebius function of x. + + ? whatnow("sin") + This function did not change + @eprog When a function was removed and the underlying functionality + is not available under a compatible interface, no equivalent is mentioned: + \bprog + ? whatnow("buchfu") + This function no longer exists + @eprog\noindent (The closest equivalent would be to set \kbd{K = bnfinit(T)} + then access \kbd{K.fu}.) + +Function: while +Class: basic +Section: programming/control +C-Name: whilepari +Prototype: vEI +Help: while(a,seq): while a is nonzero evaluate the expression sequence seq. + Otherwise 0. +Doc: while $a$ is nonzero, evaluates the expression sequence \var{seq}. The + test is made \emph{before} evaluating the $seq$, hence in particular if $a$ + is initially equal to zero the \var{seq} will not be evaluated at all. + +Function: write +Class: basic +Section: programming/specific +C-Name: write0 +Prototype: vss* +Help: write(filename,{str}*): appends the remaining arguments (same output as + print) to filename. +Doc: writes (appends) to \var{filename} the remaining arguments, and appends a + newline (same output as \kbd{print}). + + \misctitle{Variant} The high-level function \kbd{write} is expensive when many + consecutive writes are expected because it cannot use buffering. The low-level + interface \kbd{fileopen} / \kbd{filewrite} / \kbd{fileclose} is more efficient. + It also allows to truncate existing files and replace their contents. + +Function: write1 +Class: basic +Section: programming/specific +C-Name: write1 +Prototype: vss* +Help: write1(filename,{str}*): appends the remaining arguments (same output as + print1) to filename. +Doc: writes (appends) to \var{filename} the remaining arguments without a + trailing newline (same output as \kbd{print1}). + +Function: writebin +Class: basic +Section: programming/specific +C-Name: gpwritebin +Prototype: vsDG +Help: writebin(filename,{x}): write x as a binary object to file filename. + If x is omitted, write all session variables. +Doc: writes (appends) to + \var{filename} the object $x$ in binary format. This format is not human + readable, but contains the exact internal structure of $x$, and is much + faster to save/load than a string expression, as would be produced by + \tet{write}. The binary file format includes a magic number, so that such a + file can be recognized and correctly input by the regular \tet{read} or \b{r} + function. If saved objects refer to polynomial variables that are not + defined in the new session, they will be displayed as \kbd{t$n$} for some + integer $n$ (the attached variable number). + Installed functions and history objects can not be saved via this function. + + If $x$ is omitted, saves all user variables from the session, together with + their names. Reading such a ``named object'' back in a \kbd{gp} session will set + the corresponding user variable to the saved value. E.g after + \bprog + x = 1; writebin("log") + @eprog\noindent + reading \kbd{log} into a clean session will set \kbd{x} to $1$. + The relative variables priorities (see \secref{se:priority}) of new variables + set in this way remain the same (preset variables retain their former + priority, but are set to the new value). In particular, reading such a + session log into a clean session will restore all variables exactly as they + were in the original one. + + Just as a regular input file, a binary file can be compressed + using \tet{gzip}, provided the file name has the standard \kbd{.gz} + extension.\sidx{binary file} + + In the present implementation, the binary files are architecture dependent + and compatibility with future versions of \kbd{gp} is not guaranteed. Hence + binary files should not be used for long term storage (also, they are + larger and harder to compress than text files). + +Function: writetex +Class: basic +Section: programming/specific +C-Name: writetex +Prototype: vss* +Help: writetex(filename,{str}*): appends the remaining arguments (same format as + print) to filename, in TeX format. +Doc: as \kbd{write}, in \TeX\ format. See \tet{strtex} for details: + this function is essentially equivalent to calling \kbd{strtex} on remaining + arguments and writing them to file. + +Function: zeta +Class: basic +Section: transcendental +C-Name: gzeta +Prototype: Gp +Help: zeta(s): Riemann zeta function at s with s a complex or a p-adic number. +Doc: For $s \neq 1$ a complex number, Riemann's zeta + function \sidx{Riemann zeta-function} $\zeta(s)=\sum_{n\ge1}n^{-s}$, + computed using the \idx{Euler-Maclaurin} summation formula, except + when $s$ is of type integer, in which case it is computed using + Bernoulli numbers\sidx{Bernoulli numbers} for $s\le0$ or $s>0$ and + even, and using modular forms for $s>0$ and odd. Power series + are also allowed: + \bprog + ? zeta(2) - Pi^2/6 + %1 = 0.E-38 + ? zeta(1+x+O(x^3)) + %2 = 1.0000000000000000000000000000000000000*x^-1 + \ + 0.57721566490153286060651209008240243104 + O(x) + @eprog + + For $s\neq 1$ a $p$-adic number, Kubota-Leopoldt zeta function at $s$, that + is the unique continuous $p$-adic function on the $p$-adic integers + that interpolates the values of $(1 - p^{-k}) \zeta(k)$ at negative + integers $k$ such that $k \equiv 1 \pmod{p-1}$ (resp. $k$ is odd) if + $p$ is odd (resp. $p = 2$). Power series are not allowed in this case. + \bprog + ? zeta(-3+O(5^10)) + %1 = 4*5^-1 + 4 + 3*5 + 4*5^3 + 4*5^5 + 4*5^7 + O(5^9))))) + ? (1-5^3) * zeta(-3) + %2 = -1.0333333333333333333333333333333333333 + ? bestappr(%) + %3 = -31/30 + ? zeta(-3+O(5^10)) - (-31/30) + %4 = O(5^9) + @eprog + +Function: zetahurwitz +Class: basic +Section: transcendental +C-Name: zetahurwitz +Prototype: GGD0,L,b +Help: zetahurwitz(s,x,{der=0}): Hurwitz zeta function at s, x, with s not 1 and + x not a negative or zero integer. s can be a scalar, polynomial, rational + function, or power series. If der>0, compute the der'th derivative with + respect to s. +Doc: Hurwitz zeta function $\zeta(s,x)=\sum_{n\ge0}(n+x)^{-s}$ and + analytically continued, with $s\ne1$ and $x$ not a negative or zero + integer. Note that $\zeta(s,1) = \zeta(s)$. $s$ can also be a polynomial, + rational function, or power series. If \kbd{der} is positive, compute the + \kbd{der}'th derivative with respect to $s$. Note that the derivative + with respect to $x$ is simply $-s\zeta(s+1,x)$. + \bprog + ? zetahurwitz(Pi,Pi) + %1 = 0.056155444497585099925180502385781494484 + ? zetahurwitz(2,1) - zeta(2) + %2 = -2.350988701644575016 E-38 + ? zetahurwitz(Pi,3) - (zeta(Pi)-1-1/2^Pi) + %3 = -2.2040519077917890774 E-39 + ? zetahurwitz(-7/2,1) - zeta(-7/2) + %4 = -2.295887403949780289 E-41 + ? zetahurwitz(-2.3,Pi+I*log(2)) + %5 = -5.1928369229555125820137832704455696057\ + - 6.1349660138824147237884128986232049582*I + ? zetahurwitz(-1+x^2+O(x^3),1) + %6 = -0.083333333333333333333333333333333333333\ + - 0.16542114370045092921391966024278064276*x^2 + O(x^3) + ? zetahurwitz(1+x+O(x^4),2) + %7 = 1.0000000000000000000000000000000000000*x^-1\ + - 0.42278433509846713939348790991759756896\ + + 0.072815845483676724860586375874901319138*x + O(x^2) + ? zetahurwitz(2,1,2) \\ zeta''(2) + %8 = 1.9892802342989010234208586874215163815 + @eprog + + The derivative can be used to compute Barnes' multiple gamma functions. + For instance: + \bprog + ? mygamma(z)=exp(zetahurwitz(0,z,1)-zeta'(0)); + /* Alternate way to compute the gamma function */ + ? BarnesG(z)=exp(-zetahurwitz(-1,z,1)+(z-1)*lngamma(z)+zeta'(-1)); + /* Barnes G function, satisfying G(z+1)=gamma(z)*G(z): */ + ? BarnesG(6)/BarnesG(5) + % = 24.000000000000000000000000000000000002 + @eprog + +Function: zetamult +Class: basic +Section: transcendental +C-Name: zetamult_interpolate +Prototype: GDGp +Help: zetamult(s,{t=0}): multiple zeta value at integral s = [s1,...,sk]; + more generally, return Yamamoto's t-MZV interpolation (star value for t = 1). +Doc: For $s$ a vector of positive integers such that $s[1] \geq 2$, + returns the multiple zeta value (MZV) + $$\zeta(s_{1},\dots, s_{k}) = \sum_{n_{1}>\dots>n_{k}>0} + n_{1}^{-s_{1}}\dots n_{k}^{-s_{k}}$$ + of length $k$ and weight $\sum_{i} s_{i}$. + More generally, return Yamamoto's $t$-MZV interpolation evaluated at $t$: + for $t = 0$, this is the ordinary MZV; for $t = 1$, we obtain the MZSV + star value, with $\geq$ instead of strict inequalities; + and of course, for $t = \kbd{'x}$ we obtain Yamamoto's one-variable polynomial. + \bprog + ? zetamult([2,1]) - zeta(3) \\ Euler's identity + %1 = 0.E-38 + ? zetamult([2,1], 1) \\ star value + %2 = 2.4041138063191885707994763230228999815 + ? zetamult([2,1], 'x) + %3 = 1.20205[...]*x + 1.20205[...] + @eprog\noindent + If the bit precision is $B$, this function runs in time + $\tilde{O}(k(B+k)^{2})$ if $t = 0$, and $\tilde{O}(kB^{3})$ otherwise. + + In addition to the above format (\kbd{avec}), the function + also accepts a binary word format \kbd{evec} (each $s_{i}$ is replaced + by $s_{i}$ bits, all of them 0 but the last one) giving the MZV + representation as an iterated integral, and an \kbd{index} format + (if $e$ is the positive integer attached the \kbd{evec} vector of + bits, the index is the integer $e + 2^{k-2}$). The function + \kbd{zetamultconvert} allows to pass from one format to the other; the + function \kbd{zetamultall} computes simultaneously all MZVs of weight + $\sum_{i\leq k} s_{i}$ up to $n$. +Variant: Also available is \fun{GEN}{zetamult}{GEN s, long prec} for $t = 0$. + +Function: zetamultall +Class: basic +Section: transcendental +C-Name: zetamultall +Prototype: LD0,L,p +Help: zetamultall(k,{flag=0}): list of all multiple zeta values for weight + up to k. Binary digits of flag mean: 0 = zetastar values if set, + 1 = values up to duality if set, 2 = values of weight k if set + (else all values up to weight k), 3 = return the 2-component vector + [Z, M], where M is the vector of the corresponding indices m, i.e., such that + zetamult(M[i]) = Z[i]. +Doc: list of all multiple zeta values (MZVs) for weight $s_{1} + \dots + s_{r}$ + up to $k$. Binary digits of $\fl$ mean : 0 = star values if set; + 1 = values up to to duality if set (see \kbd{zetamultdual}, ignored if + star values); 2 = values of weight $k$ if set (else all values up to weight + $k$); 3 = return the 2-component vector \kbd{[Z, M]}, where $M$ is the vector + of the corresponding indices $m$, i.e., such that + \kbd{zetamult(M[i])} = \kbd{Z[i]}. Note that it is necessary to use + \kbd{zetamultconvert} to have the corresponding \kbd{avec} + $(s_{1},\dots, s_{r})$. + + With the default value $\fl=0$, the function returns a vector with $2^{k-1}-1$ + components whose $i$-th entry is the MZV of \kbd{index} $i$ (see + \kbd{zetamult}). If the bit precision is $B$, this function runs in time + $O(2^{k} k B^{2})$ for an output of size $O(2^{k} B)$. + + \bprog + ? Z = zetamultall(5); #Z \\ 2^4 - 1 MZVs of weight <= 5 + %1 = 15 + ? Z[10] + %2 = 0.22881039760335375976874614894168879193 + ? zetamultconvert(10) + %3 = Vecsmall([3, 2]) \\ @com{index $10$ corresponds to $\zeta(3,2)$} + ? zetamult(%) \\ double check + %4 = 0.22881039760335375976874614894168879193 + ? zetamult(10) \\ we can use the index directly + %5 = 0.22881039760335375976874614894168879193 + @eprog\noindent If we use flag bits 1 and 2, we avoid unnecessary + computations and copying, saving a potential factor 4: half the values + are in lower weight and computing up to duality save another rough factor 2. + Unfortunately, the indexing now no longer corresponds to the new shorter + vector of MZVs: + \bprog + ? Z = zetamultall(5, 2); #Z \\ up to duality + %6 = 9 + ? Z = zetamultall(5, 2); #Z \\ only weight 5 + %7 = 8 + ? Z = zetamultall(5, 2 + 4); #Z \\ both + %8 = 4 + @eprog\noindent So how to recover the value attached to index 10 ? Flag + bit 3 returns the actual indices used: + \bprog + ? [Z, M] = zetamultall(5, 2 + 8); M \\ other indices were not included + %9 = Vecsmall([1, 2, 4, 5, 6, 8, 9, 10, 12]) + ? Z[8] \\ index m = 10 is now in M[8] + %10 = 0.22881039760335375976874614894168879193 + ? [Z, M] = zetamultall(5, 2 + 4 + 8); M + %11 = Vecsmall([8, 9, 10, 12]) + ? Z[3] \\ index m = 10 is now in M[3] + %12 = 0.22881039760335375976874614894168879193 + @eprog\noindent The following construction automates the above + programmatically, looking up the MZVs of index $10$ ($=\zeta(3,2)$) in all + cases, without inspecting the various index sets $M$ visually: + \bprog + ? Z[vecsearch(M, 10)] \\ works in all the above settings + %13 = 0.22881039760335375976874614894168879193 + @eprog + +Function: zetamultconvert +Class: basic +Section: transcendental +C-Name: zetamultconvert +Prototype: GD1,L, +Help: zetamultconvert(a,{flag=1}): a being either an evec, avec, or index m, + converts into evec (flag=0), avec (flag=1), or index m (flag=2). +Doc: \kbd{a} being either an \kbd{evec}, \kbd{avec}, or index \kbd{m}, + converts into \kbd{evec} ($\fl=0$), \kbd{avec} ($\fl=1$), or + index \kbd{m} ($\fl=2$). + \bprog + ? zetamultconvert(10) + %1 = Vecsmall([3, 2]) + ? zetamultconvert(13) + %2 = Vecsmall([2, 2, 1]) + ? zetamultconvert(10, 0) + %3 = Vecsmall([0, 0, 1, 0, 1]) + ? zetamultconvert(13, 0) + %4 = Vecsmall([0, 1, 0, 1, 1]) + @eprog\noindent The last two lines imply that $[3,2]$ and $[2,2,1]$ + are dual (reverse order of bits and swap $0$ and $1$ in \kbd{evec} form). + Hence they have the same zeta value: + \bprog + ? zetamult([3,2]) + %5 = 0.22881039760335375976874614894168879193 + ? zetamult([2,2,1]) + %6 = 0.22881039760335375976874614894168879193 + @eprog + +Function: zetamultdual +Class: basic +Section: transcendental +C-Name: zetamultdual +Prototype: G +Help: zetamultdual(s): s being either an evec, avec, or index m, + return the dual sequence in avec format. +Doc: $s$ being either an \kbd{evec}, \kbd{avec}, or index \kbd{m}, + return the dual sequence in \kbd{avec} format. + The dual of a sequence of length $r$ and weight $k$ has length $k-r$ and + weight $k$. Duality is an involution and zeta values attached to + dual sequences are the same: + \bprog + ? zetamultdual([4]) + %1 = Vecsmall([2, 1, 1]) + ? zetamultdual(%) + %2 = Vecsmall([4]) + ? zetamult(%1) - zetamult(%2) + %3 = 0.E-38 + @eprog + In \kbd{evec} form, duality simply reverses the order of bits and swaps $0$ + and $1$: + \bprog + ? zetamultconvert([4], 0) + %4 = Vecsmall([0, 0, 0, 1]) + ? zetamultconvert([2,1,1], 0) + %5 = Vecsmall([0, 1, 1, 1]) + @eprog + +Function: znchar +Class: basic +Section: number_theoretical +C-Name: znchar +Prototype: G +Help: znchar(D): given a datum D describing a group G = (Z/NZ)^* and + a Dirichlet character chi, return the pair [G,chi]. +Doc: Given a datum $D$ describing a group $(\Z/N\Z)^{*}$ and a Dirichlet + character $\chi$, return the pair \kbd{[G, chi]}, where \kbd{G} is + \kbd{znstar(N, 1)}) and \kbd{chi} is a GP character. + + The following possibilities for $D$ are supported + + \item a nonzero \typ{INT} congruent to $0,1$ modulo $4$, return the real + character modulo $D$ given by the Kronecker symbol $(D/.)$; + + \item a \typ{INTMOD} \kbd{Mod(m, N)}, return the Conrey character + modulo $N$ of index $m$ (see \kbd{znconreylog}). + + \item a modular form space as per \kbd{mfinit}$([N,k,\chi])$ or a modular + form for such a space, return the underlying Dirichlet character $\chi$ + (which may be defined modulo a divisor of $N$ but need not be primitive). + + In the remaining cases, \kbd{G} is initialized by \kbd{znstar(N, 1)}. + + \item a pair \kbd{[G, chi]}, where \kbd{chi} is a standard GP Dirichlet + character $c = (c_{j})$ on \kbd{G} (generic character \typ{VEC} or + Conrey characters \typ{COL} or \typ{INT}); given + generators $G = \oplus (\Z/d_{j}\Z) g_{j}$, $\chi(g_{j}) = e(c_{j}/d_{j})$. + + \item a pair \kbd{[G, chin]}, where \kbd{chin} is a \emph{normalized} + representation $[n, \tilde{c}]$ of the Dirichlet character $c$; $\chi(g_{j}) + = e(\tilde{c}_{j} / n)$ where $n$ is minimal (order of $\chi$). + + \bprog + ? [G,chi] = znchar(-3); + ? G.cyc + %2 = [2] + ? chareval(G, chi, 2) + %3 = 1/2 + ? kronecker(-3,2) + %4 = -1 + ? znchartokronecker(G,chi) + %5 = -3 + ? mf = mfinit([28, 5/2, Mod(2,7)]); [f] = mfbasis(mf); + ? [G,chi] = znchar(mf); [G.mod, chi] + %7 = [7, [2]~] + ? [G,chi] = znchar(f); chi + %8 = [28, [0, 2]~] + @eprog + +Function: zncharconductor +Class: basic +Section: number_theoretical +C-Name: zncharconductor +Prototype: GG +Help: zncharconductor(G,chi): let G be znstar(q,1) and chi + be a Dirichlet character on (Z/qZ)*. Return + the conductor of chi. +Doc: Let \var{G} be attached to $(\Z/q\Z)^{*}$ (as per + \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on + $(\Z/q\Z)^{*}$ (see \secref{se:dirichletchar} or \kbd{??character}). + Return the conductor of \kbd{chi}: + \bprog + ? G = znstar(126000, 1); + ? zncharconductor(G,11) \\ primitive + %2 = 126000 + ? zncharconductor(G,1) \\ trivial character, not primitive! + %3 = 1 + ? zncharconductor(G,1009) \\ character mod 5^3 + %4 = 125 + @eprog + +Function: znchardecompose +Class: basic +Section: number_theoretical +C-Name: znchardecompose +Prototype: GGG +Help: znchardecompose(G,chi,Q): given a znstar G = (Z/NZ)^* and + a Dirichlet character chi, return the product of local characters chi_p + for p | (N,Q). +Doc: Let $N = \prod_{p} p^{e_{p}}$ and a Dirichlet character $\chi$, + we have a decomposition $\chi = \prod_{p} \chi_{p}$ into character modulo $N$ + where the conductor of $\chi_{p}$ divides $p^{e_{p}}$; it equals $p^{e_{p}}$ + for all $p$ if and only if $\chi$ is primitive. + + Given a \var{znstar} G describing a group $(\Z/N\Z)^{*}$, a Dirichlet + character \kbd{chi} and an integer $Q$, return $\prod_{p \mid (Q,N)} \chi_{p}$. + For instance, if $Q = p$ is a prime divisor of $N$, the function returns + $\chi_{p}$ (as a character modulo $N$), given as a Conrey + character (\typ{COL}). + \bprog + ? G = znstar(40, 1); + ? G.cyc + %2 = [4, 2, 2] + ? chi = [2, 1, 1]; + ? chi2 = znchardecompose(G, chi, 2) + %4 = [1, 1, 0]~ + ? chi5 = znchardecompose(G, chi, 5) + %5 = [0, 0, 2]~ + ? znchardecompose(G, chi, 3) + %6 = [0, 0, 0]~ + ? c = charmul(G, chi2, chi5) + %7 = [1, 1, 2]~ \\ t_COL: in terms of Conrey generators ! + ? znconreychar(G,c) + %8 = [2, 1, 1] \\ t_VEC: in terms of SNF generators + @eprog + +Function: znchargauss +Class: basic +Section: number_theoretical +C-Name: znchargauss +Prototype: GGDGb +Help: znchargauss(G,chi,{a=1}): given a Dirichlet character chi on + G = (Z/NZ)^*, return the complex Gauss sum g(chi,a). +Doc: Given a Dirichlet character $\chi$ on $G = (\Z/N\Z)^{*}$ (see + \kbd{znchar}), return the complex Gauss sum + $$g(\chi,a) = \sum_{n = 1}^{N} \chi(n) e(a n/N)$$ + \bprog + ? [G,chi] = znchar(-3); \\ quadratic Gauss sum: I*sqrt(3) + ? znchargauss(G,chi) + %2 = 1.7320508075688772935274463415058723670*I + ? [G,chi] = znchar(5); + ? znchargauss(G,chi) \\ sqrt(5) + %2 = 2.2360679774997896964091736687312762354 + ? G = znstar(300,1); chi = [1,1,12]~; + ? znchargauss(G,chi) / sqrt(300) - exp(2*I*Pi*11/25) \\ = 0 + %4 = 2.350988701644575016 E-38 + 1.4693679385278593850 E-39*I + ? lfuntheta([G,chi], 1) \\ = 0 + %5 = -5.79[...] E-39 - 2.71[...] E-40*I + @eprog + +Function: zncharinduce +Class: basic +Section: number_theoretical +C-Name: zncharinduce +Prototype: GGG +Help: zncharinduce(G,chi,N): let G be znstar(q,1), let chi + be a Dirichlet character mod q and let N be a multiple of q. Return + the character modulo N extending chi. +Doc: Let $G$ be attached to $(\Z/q\Z)^{*}$ (as per \kbd{G = znstar(q,1)}) + and let \kbd{chi} be a Dirichlet character on $(\Z/q\Z)^{*}$, given by + + \item a \typ{VEC}: a standard character on \kbd{bid.gen}, + + \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^{*}$ or its + Conrey logarithm; + see \secref{se:dirichletchar} or \kbd{??character}. + + Let $N$ be a multiple of $q$, return the character modulo $N$ extending + \kbd{chi}. As usual for arithmetic functions, the new modulus $N$ can be + given as a \typ{INT}, via a factorization matrix or a pair + \kbd{[N, factor(N)]}, or by \kbd{znstar(N,1)}. + + \bprog + ? G = znstar(4, 1); + ? chi = znconreylog(G,1); \\ trivial character mod 4 + ? zncharinduce(G, chi, 80) \\ now mod 80 + %3 = [0, 0, 0]~ + ? zncharinduce(G, 1, 80) \\ same using directly Conrey label + %4 = [0, 0, 0]~ + ? G2 = znstar(80, 1); + ? zncharinduce(G, 1, G2) \\ same + %4 = [0, 0, 0]~ + + ? chi = zncharinduce(G, 3, G2) \\ extend the nontrivial character mod 4 + %5 = [1, 0, 0]~ + ? [G0,chi0] = znchartoprimitive(G2, chi); + ? G0.mod + %7 = 4 + ? chi0 + %8 = [1]~ + @eprog\noindent Here is a larger example: + \bprog + ? G = znstar(126000, 1); + ? label = 1009; + ? chi = znconreylog(G, label) + %3 = [0, 0, 0, 14, 0]~ + ? [G0,chi0] = znchartoprimitive(G, label); \\ works also with 'chi' + ? G0.mod + %5 = 125 + ? chi0 \\ primitive character mod 5^3 attached to chi + %6 = [14]~ + ? G0 = znstar(N0, 1); + ? zncharinduce(G0, chi0, G) \\ induce back + %8 = [0, 0, 0, 14, 0]~ + ? znconreyexp(G, %) + %9 = 1009 + @eprog + +Function: zncharisodd +Class: basic +Section: number_theoretical +C-Name: zncharisodd +Prototype: lGG +Help: zncharisodd(G,chi): let G be znstar(N,1), let chi + be a Dirichlet character mod N, return 1 if and only if chi(-1) = -1 + and 0 otherwise. +Doc: Let $G$ be attached to $(\Z/N\Z)^{*}$ (as per \kbd{G = znstar(N,1)}) + and let \kbd{chi} be a Dirichlet character on $(\Z/N\Z)^{*}$, given by + + \item a \typ{VEC}: a standard character on \kbd{G.gen}, + + \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^{*}$ or its + Conrey logarithm; + see \secref{se:dirichletchar} or \kbd{??character}. + + Return $1$ if and only if \kbd{chi}$(-1) = -1$ and $0$ otherwise. + + \bprog + ? G = znstar(8, 1); + ? zncharisodd(G, 1) \\ trivial character + %2 = 0 + ? zncharisodd(G, 3) + %3 = 1 + ? chareval(G, 3, -1) + %4 = 1/2 + @eprog + +Function: znchartokronecker +Class: basic +Section: number_theoretical +C-Name: znchartokronecker +Prototype: GGD0,L, +Help: znchartokronecker(G,chi,{flag=0}): let G be znstar(N,1), let chi + be a Dirichlet character mod N, return the discriminant D if chi is + real equal to the Kronecker symbol (D/.) and 0 otherwise. If flag + is set, return the fundamental discriminant attached to the corresponding + primitive character. +Doc: Let $G$ be attached to $(\Z/N\Z)^{*}$ (as per \kbd{G = znstar(N,1)}) + and let \kbd{chi} be a Dirichlet character on $(\Z/N\Z)^{*}$, given by + + \item a \typ{VEC}: a standard character on \kbd{bid.gen}, + + \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^{*}$ or its + Conrey logarithm; + see \secref{se:dirichletchar} or \kbd{??character}. + + If $\fl = 0$, return the discriminant $D$ if \kbd{chi} is real equal to the + Kronecker symbol $(D/.)$ and $0$ otherwise. The discriminant $D$ is + fundamental if and only if \kbd{chi} is primitive. + + If $\fl = 1$, return the fundamental discriminant attached to the + corresponding primitive character. + + \bprog + ? G = znstar(8,1); CHARS = [1,3,5,7]; \\ Conrey labels + ? apply(t->znchartokronecker(G,t), CHARS) + %2 = [4, -8, 8, -4] + ? apply(t->znchartokronecker(G,t,1), CHARS) + %3 = [1, -8, 8, -4] + @eprog + +Function: znchartoprimitive +Class: basic +Section: number_theoretical +C-Name: znchartoprimitive +Prototype: GG +Help: znchartoprimitive(G,chi): let G be znstar(q,1) and chi + be a Dirichlet character on (Z/qZ)* of conductor q0. Return [G0,chi0], + where chi0 is the primitive character attached to chi and G0 is znstar(q0). +Doc: Let \var{G} be attached to $(\Z/q\Z)^{*}$ (as per + \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on + $(\Z/q\Z)^{*}$, of conductor $q_{0} \mid q$. + + \bprog + ? G = znstar(126000, 1); + ? [G0,chi0] = znchartoprimitive(G,11) + ? G0.mod + %3 = 126000 + ? chi0 + %4 = 11 + ? [G0,chi0] = znchartoprimitive(G,1);\\ trivial character, not primitive! + ? G0.mod + %6 = 1 + ? chi0 + %7 = []~ + ? [G0,chi0] = znchartoprimitive(G,1009) + ? G0.mod + %4 = 125 + ? chi0 + %5 = [14]~ + @eprog\noindent Note that \kbd{znconreyconductor} is more efficient since + it can return $\chi_{0}$ and its conductor $q_{0}$ without needing to + initialize $G_{0}$. The price to pay is a more cryptic format and the need to + initalize $G_{0}$ later, but that needs to be done only once for all characters + with conductor $q_{0}$. + +Function: znconreychar +Class: basic +Section: number_theoretical +C-Name: znconreychar +Prototype: GG +Help: znconreychar(G,m): Dirichlet character attached to m in (Z/qZ)* + in Conrey's notation, where G is znstar(q,1). +Doc: Given a \var{znstar} $G$ attached to $(\Z/q\Z)^{*}$ (as per + \kbd{G = znstar(q,1)}), this function returns the Dirichlet character + attached to $m \in (\Z/q\Z)^{*}$ via Conrey's logarithm, which + establishes a ``canonical'' bijection between $(\Z/q\Z)^{*}$ and its dual. + + Let $q = \prod_{p} p^{e_{p}}$ be the factorization of $q$ into distinct primes. + For all odd $p$ with $e_{p} > 0$, let $g_{p}$ be the element in $(\Z/q\Z)^{*}$ + which is + + \item congruent to $1$ mod $q/p^{e_{p}}$, + + \item congruent mod $p^{e_{p}}$ to the smallest positive integer that generates + $(\Z/p^{2}\Z)^{*}$. + + For $p = 2$, we let $g_{4}$ (if $2^{e_{2}} \geq 4$) and $g_{8}$ (if furthermore + ($2^{e_{2}} \geq 8$) be the elements in $(\Z/q\Z)^{*}$ which are + + \item congruent to $1$ mod $q/2^{e_{2}}$, + + \item $g_{4} = -1 \mod 2^{e_{2}}$, + + \item $g_{8} = 5 \mod 2^{e_{2}}$. + + Then the $g_{p}$ (and the extra $g_{4}$ and $g_{8}$ if $2^{e_{2}}\geq 2$) are + independent generators of $(\Z/q\Z)^{*}$, i.e. every $m$ in $(\Z/q\Z)^{*}$ + can be written uniquely as $\prod_{p} g_{p}^{m_{p}}$, where $m_{p}$ is defined + modulo the + order $o_{p}$ of $g_{p}$ and $p \in S_{q}$, the set of prime divisors of $q$ + together with $4$ if $4 \mid q$ and $8$ if $8 \mid q$. Note that the $g_{p}$ + are in general \emph{not} SNF generators as produced by \kbd{znstar} whenever + $\omega(q) \geq 2$, although their number is the same. They however allow + to handle the finite abelian group $(\Z/q\Z)^{*}$ in a fast and elegant way. + (Which unfortunately does not generalize to ray class groups or Hecke + characters.) + + The Conrey logarithm of $m$ is the vector $(m_{p})_{p\in S_{q}}$, obtained + via \tet{znconreylog}. The Conrey character $\chi_{q}(m,\cdot)$ attached to + $m$ mod $q$ maps + each $g_{p}$, $p\in S_{q}$ to $e(m_{p} / o_{p})$, where $e(x) = \exp(2i\pi x)$. + This function returns the Conrey character expressed in the standard PARI + way in terms of the SNF generators \kbd{G.gen}. + + \bprog + ? G = znstar(8,1); + ? G.cyc + %2 = [2, 2] \\ Z/2 x Z/2 + ? G.gen + %3 = [7, 3] + ? znconreychar(G,1) \\ 1 is always the trivial character + %4 = [0, 0] + ? znconreychar(G,2) \\ 2 is not coprime to 8 !!! + *** at top-level: znconreychar(G,2) + *** ^----------------- + *** znconreychar: elements not coprime in Zideallog: + 2 + 8 + *** Break loop: type 'break' to go back to GP prompt + break> + + ? znconreychar(G,3) + %5 = [0, 1] + ? znconreychar(G,5) + %6 = [1, 1] + ? znconreychar(G,7) + %7 = [1, 0] + @eprog\noindent We indeed get all 4 characters of $(\Z/8\Z)^{*}$. + + For convenience, we allow to input the \emph{Conrey logarithm} of $m$ + instead of $m$: + \bprog + ? G = znstar(55, 1); + ? znconreychar(G,7) + %2 = [7, 0] + ? znconreychar(G, znconreylog(G,7)) + %3 = [7, 0] + @eprog + +Function: znconreyconductor +Class: basic +Section: number_theoretical +C-Name: znconreyconductor +Prototype: GGD& +Help: znconreyconductor(G,chi,{&chi0}): let G be znstar(q,1) and chi + be a Dirichlet character on (Z/qZ)* given by its Conrey logarithm. Return + the conductor of chi, and set chi0 to (the Conrey logarithm of) the + attached primitive character. If chi0 != chi, return the conductor + and its factorization. +Doc: Let \var{G} be attached to $(\Z/q\Z)^{*}$ (as per + \kbd{G = znstar(q, 1)}) and \kbd{chi} be a Dirichlet character on + $(\Z/q\Z)^{*}$, given by + + \item a \typ{VEC}: a standard character on \kbd{bid.gen}, + + \item a \typ{INT} or a \typ{COL}: a Conrey index in $(\Z/q\Z)^{*}$ or its + Conrey logarithm; + see \secref{se:dirichletchar} or \kbd{??character}. + + Return the conductor of \kbd{chi}, as the \typ{INT} \kbd{bid.mod} + if \kbd{chi} is primitive, and as a pair \kbd{[N, faN]} (with \kbd{faN} the + factorization of $N$) otherwise. + + If \kbd{chi0} is present, set it to the Conrey logarithm of the attached + primitive character. + + \bprog + ? G = znstar(126000, 1); + ? znconreyconductor(G,11) \\ primitive + %2 = 126000 + ? znconreyconductor(G,1) \\ trivial character, not primitive! + %3 = [1, matrix(0,2)] + ? N0 = znconreyconductor(G,1009, &chi0) \\ character mod 5^3 + %4 = [125, Mat([5, 3])] + ? chi0 + %5 = [14]~ + ? G0 = znstar(N0, 1); \\ format [N,factor(N)] accepted + ? znconreyexp(G0, chi0) + %7 = 9 + ? znconreyconductor(G0, chi0) \\ now primitive, as expected + %8 = 125 + @eprog\noindent The group \kbd{G0} is not computed as part of + \kbd{znconreyconductor} because it needs to be computed only once per + conductor, not once per character. + +Function: znconreyexp +Class: basic +Section: number_theoretical +C-Name: znconreyexp +Prototype: GG +Help: znconreyexp(G,chi): Conrey exponential attached to G = + znstar(q, 1). Returns the element m in (Z/qZ)^* attached to the character + chi on G: znconreylog(G, m) = chi. +Doc: Given a \var{znstar} $G$ attached to $(\Z/q\Z)^{*}$ (as per + \kbd{G = znstar(q, 1)}), this function returns the Conrey exponential of + the character \var{chi}: it returns the integer + $m \in (\Z/q\Z)^{*}$ such that \kbd{znconreylog(G, $m$)} is \var{chi}. + + The character \var{chi} is given either as a + + \item \typ{VEC}: in terms of the generators \kbd{G.gen}; + + \item \typ{COL}: a Conrey logarithm. + + \bprog + ? G = znstar(126000, 1) + ? znconreylog(G,1) + %2 = [0, 0, 0, 0, 0]~ + ? znconreyexp(G,%) + %3 = 1 + ? G.cyc \\ SNF generators + %4 = [300, 12, 2, 2, 2] + ? chi = [100, 1, 0, 1, 0]; \\ some random character on SNF generators + ? znconreylog(G, chi) \\ in terms of Conrey generators + %6 = [0, 3, 3, 0, 2]~ + ? znconreyexp(G, %) \\ apply to a Conrey log + %7 = 18251 + ? znconreyexp(G, chi) \\ ... or a char on SNF generators + %8 = 18251 + ? znconreychar(G,%) + %9 = [100, 1, 0, 1, 0] + @eprog + +Function: znconreylog +Class: basic +Section: number_theoretical +C-Name: znconreylog +Prototype: GG +Help: znconreylog(G,m): Conrey logarithm attached to m in (Z/qZ)*, + where G is znstar(q,1). +Doc: Given a \var{znstar} attached to $(\Z/q\Z)^{*}$ (as per + \kbd{G = znstar(q,1)}), this function returns the Conrey logarithm of + $m \in (\Z/q\Z)^{*}$. + + Let $q = \prod_{p} p^{e_{p}}$ be the factorization of $q$ into distinct primes, + where we assume $e_{2} = 0$ or $e_{2} \geq 2$. (If $e_{2} = 1$, we can ignore + $2$ from the factorization, as if we replaced $q$ by $q/2$, since + $(\Z/q\Z)^{*} \sim (\Z/(q/2)\Z)^{*}$.) + + For all odd $p$ with $e_{p} > 0$, let $g_{p}$ be the element in $(\Z/q\Z)^{*}$ + which is + + \item congruent to $1$ mod $q/p^{e_{p}}$, + + \item congruent mod $p^{e_{p}}$ to the smallest positive integer that generates + $(\Z/p^{2}\Z)^{*}$. + + For $p = 2$, we let $g_{4}$ (if $2^{e_{2}} \geq 4$) and $g_{8}$ (if furthermore + ($2^{e_{2}} \geq 8$) be the elements in $(\Z/q\Z)^{*}$ which are + + \item congruent to $1$ mod $q/2^{e_{2}}$, + + \item $g_{4} = -1 \mod 2^{e_{2}}$, + + \item $g_{8} = 5 \mod 2^{e_{2}}$. + + Then the $g_{p}$ (and the extra $g_{4}$ and $g_{8}$ if $2^{e_{2}}\geq 2$) are + independent generators of $\Z/q\Z^{*}$, i.e. every $m$ in $(\Z/q\Z)^{*}$ can be + written uniquely as $\prod_{p} g_{p}^{m_{p}}$, where $m_{p}$ is defined modulo + the order $o_{p}$ of $g_{p}$ and $p \in S_{q}$, the set of prime divisors of + $q$ together with $4$ if $4 \mid q$ and $8$ if $8 \mid q$. Note that the + $g_{p}$ + are in general \emph{not} SNF generators as produced by \kbd{znstar} whenever + $\omega(q) \geq 2$, although their number is the same. They however allow + to handle the finite abelian group $(\Z/q\Z)^{*}$ in a fast and elegant way. + (Which unfortunately does not generalize to ray class groups or Hecke + characters.) + + The Conrey logarithm of $m$ is the vector $(m_{p})_{p\in S_{q}}$. The inverse + function \tet{znconreyexp} recovers the Conrey label $m$ from a character. + + \bprog + ? G = znstar(126000, 1); + ? znconreylog(G,1) + %2 = [0, 0, 0, 0, 0]~ + ? znconreyexp(G, %) + %3 = 1 + ? znconreylog(G,2) \\ 2 is not coprime to modulus !!! + *** at top-level: znconreylog(G,2) + *** ^----------------- + *** znconreylog: elements not coprime in Zideallog: + 2 + 126000 + *** Break loop: type 'break' to go back to GP prompt + break> + ? znconreylog(G,11) \\ wrt. Conrey generators + %4 = [0, 3, 1, 76, 4]~ + ? log11 = ideallog(,11,G) \\ wrt. SNF generators + %5 = [178, 3, -75, 1, 0]~ + @eprog\noindent + + For convenience, we allow to input the ordinary discrete log of $m$, + $\kbd{ideallog(,m,bid)}$, which allows to convert discrete logs + from \kbd{bid.gen} generators to Conrey generators. + \bprog + ? znconreylog(G, log11) + %7 = [0, 3, 1, 76, 4]~ + @eprog\noindent We also allow a character (\typ{VEC}) on \kbd{bid.gen} and + return its representation on the Conrey generators. + \bprog + ? G.cyc + %8 = [300, 12, 2, 2, 2] + ? chi = [10,1,0,1,1]; + ? znconreylog(G, chi) + %10 = [1, 3, 3, 10, 2]~ + ? n = znconreyexp(G, chi) + %11 = 84149 + ? znconreychar(G, n) + %12 = [10, 1, 0, 1, 1] + @eprog + +Function: zncoppersmith +Class: basic +Section: number_theoretical +C-Name: zncoppersmith +Prototype: GGGDG +Help: zncoppersmith(P,N,X,{B=N}): finds all integers x + with |x| <= X such that gcd(N, P(x)) >= B. The parameter X should be smaller + than exp((log B)^2 / (deg(P) log N)) and the leading coefficient of P should be + coprime to N. +Doc: \idx{Coppersmith}'s algorithm. $N$ being an integer and $P\in \Z[t]$, + finds in polynomial time in $\log(N)$ and $d = \text{deg}(P)$ all integers $x$ + with $|x| \leq X$ such that + $$\gcd(N, P(x)) \geq B.$$ + This is a famous application of the \idx{LLL} algorithm meant to help in the + factorization of $N$. Notice that $P$ may be reduced modulo $N\Z[t]$ without + affecting the situation. The parameter $X$ must not be too large: assume for + now that the leading coefficient of $P$ is coprime to $N$, then we must have + $$d \log X \log N < \log^{2} B,$$ i.e., $X < N^{1/d}$ when $B = N$. Let now + $P_{0}$ be the gcd of the leading coefficient of $P$ and $N$. In applications + to factorization, we should have $P_{0} = 1$; otherwise, either $P_{0} = N$ and + we can reduce the degree of $P$, or $P_{0}$ is a non trivial factor of $N$. For + completeness, we nevertheless document the exact conditions that $X$ must + satisfy in this case: let $p := \log_{N} P_{0}$, $b := \log_{N} B$, + $x := \log_{N} X$, then + + \item either $p \geq d / (2d-1)$ is large and we must have $x d < 2b - 1$; + + \item or $p < d / (2d-1)$ and we must have both $p < b < 1 - p + p/d$ + and $x(d + p(1-2d)) < (b - p)^{2}$. Note that this reduces to + $x d < b^{2}$ when $p = 0$, i.e., the condition described above. + + Some $x$ larger than $X$ may be returned if you are + very lucky. The routine runs in polynomial time in $\log N$ and $d$ + but the smaller $B$, or the larger $X$, the slower. + The strength of Coppersmith method is the ability to find roots modulo a + general \emph{composite} $N$: if $N$ is a prime or a prime power, + \tet{polrootsmod} or \tet{polrootspadic} will be much faster. + + We shall now present two simple applications. The first one is + finding nontrivial factors of $N$, given some partial information on the + factors; in that case $B$ must obviously be smaller than the largest + nontrivial divisor of $N$. + \bprog + setrand(1); \\ to make the example reproducible + [a,b] = [10^30, 10^31]; D = 20; + p = randomprime([a,b]); + q = randomprime([a,b]); N = p*q; + \\ assume we know 0) p | N; 1) p in [a,b]; 2) the last D digits of p + p0 = p % 10^D; + + ? L = zncoppersmith(10^D*x + p0, N, b \ 10^D, a) + time = 1ms. + %6 = [738281386540] + ? gcd(L[1] * 10^D + p0, N) == p + %7 = 1 + @eprog\noindent and we recovered $p$, faster than by trying all + possibilities $ x < 10^{11}$. + + The second application is an attack on RSA with low exponent, when the + message $x$ is short and the padding $P$ is known to the attacker. We use + the same RSA modulus $N$ as in the first example: + \bprog + setrand(1); + P = random(N); \\ known padding + e = 3; \\ small public encryption exponent + X = floor(N^0.3); \\ N^(1/e - epsilon) + x0 = random(X); \\ unknown short message + C = lift( (Mod(x0,N) + P)^e ); \\ known ciphertext, with padding P + zncoppersmith((P + x)^3 - C, N, X) + + \\ result in 244ms. + %14 = [2679982004001230401] + + ? %[1] == x0 + %15 = 1 + @eprog\noindent + We guessed an integer of the order of $10^{18}$, almost instantly. + +Function: znlog +Class: basic +Section: number_theoretical +C-Name: znlog0 +Prototype: GGDG +Help: znlog(x,g,{o}): return the discrete logarithm of x in + (Z/nZ)* in base g. If present, o represents the multiplicative + order of g. Return [] if no solution exist. +Doc: This functions allows two distinct modes of operation depending + on $g$: + + \item if $g$ is the output of \tet{znstar} (with initialization), + we compute the discrete logarithm of $x$ with respect to the generators + contained in the structure. See \tet{ideallog} for details. + + \item else $g$ is an explicit element in $(\Z/N\Z)^{*}$, we compute the + discrete logarithm of $x$ in $(\Z/N\Z)^{*}$ in base $g$. The rest of this + entry describes the latter possibility. + + The result is $[]$ when $x$ is not a power of $g$, though the function may + also enter an infinite loop in this case. + + If present, $o$ represents the multiplicative order of $g$, see + \secref{se:DLfun}; the preferred format for this parameter is + \kbd{[ord, factor(ord)]}, where \kbd{ord} is the order of $g$. + This provides a definite speedup when the discrete log problem is simple: + \bprog + ? p = nextprime(10^4); g = znprimroot(p); o = [p-1, factor(p-1)]; + ? for(i=1,10^4, znlog(i, g, o)) + time = 163 ms. + ? for(i=1,10^4, znlog(i, g)) + time = 200 ms. \\ a little slower + @eprog + + The result is undefined if $g$ is not invertible mod $N$ or if the supplied + order is incorrect. + + This function uses + + \item a combination of generic discrete log algorithms (see below). + + \item in $(\Z/N\Z)^{*}$ when $N$ is prime: a linear sieve index calculus + method, suitable for $N < 10^{50}$, say, is used for large prime divisors of + the order. + + The generic discrete log algorithms are: + + \item Pohlig-Hellman algorithm, to reduce to groups of prime order $q$, + where $q | p-1$ and $p$ is an odd prime divisor of $N$, + + \item Shanks baby-step/giant-step ($q < 2^{32}$ is small), + + \item Pollard rho method ($q > 2^{32}$). + + The latter two algorithms require $O(\sqrt{q})$ operations in the group on + average, hence will not be able to treat cases where $q > 10^{30}$, say. + In addition, Pollard rho is not able to handle the case where there are no + solutions: it will enter an infinite loop. + \bprog + ? g = znprimroot(101) + %1 = Mod(2,101) + ? znlog(5, g) + %2 = 24 + ? g^24 + %3 = Mod(5, 101) + + ? G = znprimroot(2 * 101^10) + %4 = Mod(110462212541120451003, 220924425082240902002) + ? znlog(5, G) + %5 = 76210072736547066624 + ? G^% == 5 + %6 = 1 + ? N = 2^4*3^2*5^3*7^4*11; g = Mod(13, N); znlog(g^110, g) + %7 = 110 + ? znlog(6, Mod(2,3)) \\ no solution + %8 = [] + @eprog\noindent For convenience, $g$ is also allowed to be a $p$-adic number: + \bprog + ? g = 3+O(5^10); znlog(2, g) + %1 = 1015243 + ? g^% + %2 = 2 + O(5^10) + @eprog +Variant: The function + \fun{GEN}{znlog}{GEN x, GEN g, GEN o} is also available + +Function: znorder +Class: basic +Section: number_theoretical +C-Name: znorder +Prototype: GDG +Help: znorder(x,{o}): order of the integermod x in (Z/nZ)*. + Optional o represents a multiple of the order of the element. +Description: + (gen,?int):int znorder($1, $2) +Doc: $x$ must be an integer mod $n$, and the + result is the order of $x$ in the multiplicative group $(\Z/n\Z)^{*}$. Returns + an error if $x$ is not invertible. + The parameter o, if present, represents a nonzero + multiple of the order of $x$, see \secref{se:DLfun}; the preferred format for + this parameter is \kbd{[ord, factor(ord)]}, where \kbd{ord = eulerphi(n)} + is the cardinality of the group. + +Function: znprimroot +Class: basic +Section: number_theoretical +C-Name: znprimroot +Prototype: G +Help: znprimroot(n): returns a primitive root of n when it exists. +Doc: returns a primitive root (generator) of $(\Z/n\Z)^{*}$, whenever this + latter group is cyclic ($n = 4$ or $n = 2p^{k}$ or $n = p^{k}$, where $p$ is an + odd prime and $k \geq 0$). If the group is not cyclic, the function will raise an + exception. If $n$ is a prime power, then the smallest positive primitive + root is returned. This may not be true for $n = 2p^{k}$, $p$ odd. + + Note that this function requires factoring $p-1$ for $p$ as above, + in order to determine the exact order of elements in + $(\Z/n\Z)^{*}$: this is likely to be costly if $p$ is large. + +Function: znstar +Class: basic +Section: number_theoretical +C-Name: znstar0 +Prototype: GD0,L, +Help: znstar(n,{flag=0}): 3-component vector v = [no,cyc,gen], giving the + structure of the abelian group (Z/nZ)^*; + no is the order (i.e. eulerphi(n)), cyc is a vector of cyclic components, + and gen is a vector giving the corresponding generators. +Doc: gives the structure of the multiplicative group $(\Z/n\Z)^{*}$. + The output $G$ depends on the value of \fl: + + \item $\fl = 0$ (default), an abelian group structure $[h,d,g]$, + where $h = \phi(n)$ is the order (\kbd{G.no}), $d$ (\kbd{G.cyc}) + is a $k$-component row-vector $d$ of integers $d_{i}$ such that $d_{i}>1$, + $d_{i} \mid d_{i-1}$ for $i \ge 2$ and + $$ (\Z/n\Z)^{*} \simeq \prod_{i=1}^{k} (\Z/d_{i}\Z), $$ + and $g$ (\kbd{G.gen}) is a $k$-component row vector giving generators of + the image of the cyclic groups $\Z/d_{i}\Z$. + + \item $\fl = 1$ the result is a \kbd{bid} structure; + this allows computing discrete logarithms using \tet{znlog} (also in the + noncyclic case!). + + \bprog + ? G = znstar(40) + %1 = [16, [4, 2, 2], [Mod(17, 40), Mod(21, 40), Mod(11, 40)]] + ? G.no \\ eulerphi(40) + %2 = 16 + ? G.cyc \\ cycle structure + %3 = [4, 2, 2] + ? G.gen \\ generators for the cyclic components + %4 = [Mod(17, 40), Mod(21, 40), Mod(11, 40)] + ? apply(znorder, G.gen) + %5 = [4, 2, 2] + @eprog\noindent For user convenience, we define \kbd{znstar(0)} as + \kbd{[2, [2], [-1]]}, corresponding to $\Z^{*}$, but $\fl = 1$ is not + implemented in this trivial case. + +Function: znsubgroupgenerators +Class: basic +Section: number_theoretical +C-Name: znsubgroupgenerators +Prototype: GD0,L, +Help: znsubgroupgenerators(H,{flag=0}): finds generators of the subgroup H + of (Z/fZ)^*; H is given by a vector of length f of 1/0 values: the a-th component is 1 + if and only if a belongs to H. +Doc: Finds a minimal set of generators for the subgroup of $(\Z/f\Z)^{*}$ + given by a vector (or vectorsmall) $H$ of length $f$: + for $1\leq a\leq f$, \kbd{H[a]} is 1 or 0 according as $a\in H_{F}$ + or $a\not\in H_{F}$. In most PARI functions, subgroups of an abelian group + are given as HNF left-divisors of a diagonal matrix, representing the + discrete logarithms of the subgroup generators in terms of a fixed + generators for the group cyclic components. The present function + allows to convert an enumeration of the subgroup elements to this + representation as follows: + \bprog + ? G = znstar(f, 1); + ? v = znsubgroupgenerators(H); + ? subHNF(G, v) = mathnfmodid(Mat([znlog(h, G) | h<-v]), G.cyc); + @eprog\noindent The function \kbd{subHNF} can be applied to any + elements of $(\Z/f\Z)^{*}$, yielding the subgroup they generate, but using + \kbd{znsubgroupgenerators} first allows to reduce the number of discrete + logarithms to be computed. + + For example, if $H=\{\,1,4,11,14\,\}\subset(\Z/15\Z)^{\times}$, + then we have + \bprog + ? f = 15; H = vector(f); H[1]=H[4]=H[11]=H[14] = 1; + ? v = znsubgroupgenerators(H) + %2 = [4, 11] + ? G = znstar(f, 1); G.cyc + %3 = [4, 2] + ? subHNF(G, v) + %4 = + [2 0] + + [0 1] + ? subHNF(G, [1,4,11,14]) + %5 = + [2 0] + + [0 1] + @eprog\noindent This function is mostly useful when $f$ is large + and $H$ has small index: if $H$ has few elements, one may just use + \kbd{subHNF} directly on the elements of $H$. For instance, let + $K = \Q(\zeta_{p}, \sqrt{m}) \subset L = \Q(\zeta_{f})$, where $p$ is + a prime, $\sqrt{m}$ is a quadratic number and $f$ is the conductor of the + abelian extension $K/\Q$. The following GP script creates $H$ as the Galois + group of $L/K$, as a subgroub of $(\Z/fZ)^{*}$: + \bprog + HK(m, p, flag = 0)= + { my(d = quaddisc(m), f = lcm(d, p), H); + H = vectorsmall(f, a, a % p == 1 && kronecker(d,a) > 0); + [f, znsubgroupgenerators(H,flag)]; + } + ? [f, v] = HK(36322, 5) + time = 193 ms. + %1 = [726440, [41, 61, 111, 131]] + ? G = znstar(f,1); G.cyc + %2 = [1260, 12, 2, 2, 2, 2] + ? A = subHNF(G, v) + %3 = + [2 0 1 1 0 1] + + [0 4 0 0 0 2] + + [0 0 1 0 0 0] + + [0 0 0 1 0 0] + + [0 0 0 0 1 0] + + [0 0 0 0 0 1] + \\ Double check + ? p = 5; d = quaddisc(36322); + ? w = select(a->a % p == 1 && kronecker(d,a) > 0, [1..f]); #w + time = 133 ms. + %5 = 30240 \\ w enumerates the elements of H + ? subHNF(G, w) == A \\ same result, about twice slower + time = 242 ms. + %6 = 1 + @eprog\noindent + This shows that $K=\Q(\sqrt{36322},\zeta_{5})$ is contained in + $\Q(\zeta_{726440})$ and $H=\langle 41, 61, 111, 131 \rangle$. + Note that $H=\langle 41\rangle\langle 61\rangle\langle 111 \rangle + \langle 131\rangle$ is not a direct product. If $\fl=1$, then the function + finds generators which decompose $H$ to direct factors: + \bprog + ? HK(36322, 5, 1) + %3 = [726440, [41, 31261, 324611, 506221]] + @eprog\noindent This time + $H=\langle 41\rangle\times \langle 31261\rangle \times + \langle 324611 \rangle \times \langle 506221 \rangle$. + diff --git a/tests/rundoctest.py b/tests/rundoctest.py index cde35b69..a584c634 100755 --- a/tests/rundoctest.py +++ b/tests/rundoctest.py @@ -2,15 +2,16 @@ import os import sys +import traceback # Autogen tests must be run in the root dir, and with the proper module path path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)) os.chdir(path) sys.path.append(path) -import autogen -import cypari2 import doctest +import cypari2 + # The doctests assume utf-8 encoding cypari2.string_utils.encoding = "utf-8" @@ -24,20 +25,29 @@ pari = cypari2.Pari() pari.default("debugmem", 0) +modules = [cypari2.closure, cypari2.convert, cypari2.gen, + cypari2.handle_error, cypari2.pari_instance, cypari2.stack, + cypari2.string_utils] +try: + import autogen + modules.extend([ + autogen.doc, autogen.generator, autogen.parser]) +except ImportError: + print("Skipping autogen tests") failed = 0 attempted = 0 -for mod in [cypari2.closure, cypari2.convert, cypari2.gen, - cypari2.handle_error, cypari2.pari_instance, cypari2.stack, - cypari2.string_utils, - autogen.doc, autogen.generator, autogen.parser, - autogen.paths]: - +for mod in modules: print("="*80) print("Testing {}".format(mod.__name__)) - test = doctest.testmod(mod, optionflags=doctest.ELLIPSIS|doctest.REPORT_NDIFF, verbose=False) - failed += test.failed - attempted += test.attempted + try: + test = doctest.testmod(mod, optionflags=doctest.ELLIPSIS|doctest.REPORT_NDIFF, verbose=False) + failed += test.failed + attempted += test.attempted + except Exception: + traceback.print_exc() + failed += 1 + attempted += 1 print("="*80) print("Summary result for cypari2:") diff --git a/tests/test.c b/tests/test.c new file mode 100644 index 00000000..8a583626 --- /dev/null +++ b/tests/test.c @@ -0,0 +1,33 @@ +// Simple test program using the PARI library +// to compute zeta(2) and factor a polynomial over a finite field, as in the README. +// compile with: gcc -v test.c -o test -I/usr/local/include -L/usr/local/bin -lpari -lgmp + +#include + +int main() { + pari_init(100000000,2); + + // Compute zeta(2) + GEN z2 = szeta(2, DEFAULTPREC); + pari_printf("zeta(2) = %Ps\n", z2); + + // p = x^3 + x^2 + x - 1 + GEN gen_3 = stoi(3); + GEN x = pol_x(0); + GEN p = gadd(gadd(gadd(gpow(x, gen_3, DEFAULTPREC), gpow(x, gen_2, DEFAULTPREC)), x), gen_m1); + pari_printf("p = %Ps\n", p); + + // modulus = y^3 + y^2 + y - 1 + GEN y = pol_x(1); + GEN modulus = gadd(gadd(gadd(gpow(y, gen_3, DEFAULTPREC), gpow(y, gen_2, DEFAULTPREC)), y), gen_m1); + setvarn(modulus, 1); + pari_printf("modulus = %Ps\n", modulus); + + // Factor p over F_3[y]/(modulus) + GEN fq = factorff(p, gen_3, modulus); + GEN centered = centerlift(lift(fq)); + pari_printf("centerlift(lift(fq)) = %Ps\n", centered); + + pari_close(); + return 0; +} diff --git a/tests/test.pyx b/tests/test.pyx new file mode 100644 index 00000000..ac37b838 --- /dev/null +++ b/tests/test.pyx @@ -0,0 +1,36 @@ +# Simple test program using the PARI library in Cython +# to compute zeta(2) and factor a polynomial over a finite field, as in the README. + +from cypari2.paridecl cimport pari_printf, pari_init, pari_close, DEFAULTPREC, szeta, stoi, pol_x, gpow, gadd, factorff, lift, centerlift, setvarn, gen_2, gen_m1, gen_0, INIT_DFTm, pari_init_opts, pari_mainstack +from cypari2.types cimport GEN +from cypari2.closure cimport _pari_init_closure +from cypari2.stack cimport (new_gen, new_gen_noclear, clear_stack, + set_pari_stack_size, before_resize, after_resize) +from libc.stdio cimport printf + +def main(): + + pari_init(100000000, 2) + + # Compute zeta(2) + cdef GEN z2 = szeta(2, DEFAULTPREC) + pari_printf(b"zeta(2) = %Ps\n", z2) + + # p = x^3 + x^2 + x - 1 + cdef GEN gen_3 = stoi(3) + cdef GEN x = pol_x(0) + cdef GEN p = gadd(gadd(gadd(gpow(x, gen_3, DEFAULTPREC), gpow(x, gen_2, DEFAULTPREC)), x), gen_m1) + pari_printf(b"p = %Ps\n", p) + + # modulus = y^3 + y^2 + y - 1 + cdef GEN y = pol_x(1) + cdef GEN modulus = gadd(gadd(gadd(gpow(y, gen_3, DEFAULTPREC), gpow(y, gen_2, DEFAULTPREC)), y), gen_m1) + setvarn(modulus, 1) + pari_printf(b"modulus = %Ps\n", modulus) + + # Factor p over F_3[y]/(modulus) + cdef GEN fq = factorff(p, gen_3, modulus) + cdef GEN centered = centerlift(lift(fq)) + pari_printf(b"centerlift(lift(fq)) = %Ps\n", centered) + + pari_close() diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..856d6814 --- /dev/null +++ b/uv.lock @@ -0,0 +1,684 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "bashlex" +version = "0.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/60/aae0bb54f9af5e0128ba90eb83d8d0d506ee8f0475c4fdda3deeda20b1d2/bashlex-0.18.tar.gz", hash = "sha256:5bb03a01c6d5676338c36fd1028009c8ad07e7d61d8a1ce3f513b7fff52796ee", size = 68742, upload-time = "2023-01-18T15:21:26.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/be/6985abb1011fda8a523cfe21ed9629e397d6e06fb5bae99750402b25c95b/bashlex-0.18-py2.py3-none-any.whl", hash = "sha256:91d73a23a3e51711919c1c899083890cdecffc91d8c088942725ac13e9dcfffa", size = 69539, upload-time = "2023-01-18T15:21:24.167Z" }, +] + +[[package]] +name = "bracex" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/9a/fec38644694abfaaeca2798b58e276a8e61de49e2e37494ace423395febc/bracex-2.6.tar.gz", hash = "sha256:98f1347cd77e22ee8d967a30ad4e310b233f7754dbf31ff3fceb76145ba47dc7", size = 26642, upload-time = "2025-06-22T19:12:31.254Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" }, +] + +[[package]] +name = "build" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "os_name == 'nt'" }, + { name = "packaging" }, + { name = "pyproject-hooks" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/1c/23e33405a7c9eac261dff640926b8b5adaed6a6eb3e1767d441ed611d0c0/build-1.3.0.tar.gz", hash = "sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397", size = 48544, upload-time = "2025-08-01T21:27:09.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/8c/2b30c12155ad8de0cf641d76a8b396a16d2c36bc6d50b621a62b7c4567c1/build-1.3.0-py3-none-any.whl", hash = "sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4", size = 23382, upload-time = "2025-08-01T21:27:07.844Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "cibuildwheel" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bashlex" }, + { name = "bracex" }, + { name = "build" }, + { name = "certifi" }, + { name = "dependency-groups" }, + { name = "filelock" }, + { name = "humanize" }, + { name = "packaging" }, + { name = "patchelf", marker = "(platform_machine == 'aarch64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'arm64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "platformdirs" }, + { name = "pyelftools" }, + { name = "wheel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/33/c3e5884a4f996d9138ace03464d0396752ec8c81adada549421bc68d185f/cibuildwheel-3.2.0.tar.gz", hash = "sha256:03ceab277255dc6c6451b25aad78844f4c07b03e410ee7411e9045b20ef6466f", size = 354877, upload-time = "2025-09-22T20:46:24.522Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/b0/cbf2260b9cc2fea23abd2fac607b4d3692dfd250062fba3523b8008847bd/cibuildwheel-3.2.0-py3-none-any.whl", hash = "sha256:5349f85b89ed63d53bf79315996adb9d4e507c4b69dacb480c1eef7fddde21e1", size = 126344, upload-time = "2025-09-22T20:46:22.157Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cypari2" +source = { editable = "." } +dependencies = [ + { name = "cysignals" }, +] + +[package.dev-dependencies] +dev = [ + { name = "build" }, + { name = "cibuildwheel" }, + { name = "cython" }, + { name = "meson" }, + { name = "meson-python" }, + { name = "ninja" }, + { name = "pkgconf" }, + { name = "pytest" }, +] +doc = [ + { name = "sphinx" }, +] + +[package.metadata] +requires-dist = [{ name = "cysignals", specifier = ">=1.11.3" }] + +[package.metadata.requires-dev] +dev = [ + { name = "build", specifier = ">=1.3.0" }, + { name = "cibuildwheel", specifier = ">=2.23.3" }, + { name = "cython", specifier = ">=3.1.4" }, + { name = "meson", specifier = ">=1.9.0" }, + { name = "meson-python", specifier = ">=0.18.0" }, + { name = "ninja", specifier = ">=1.13.0" }, + { name = "pkgconf", specifier = ">=2.4.3.post2" }, + { name = "pytest", specifier = ">=8.4.2" }, +] +doc = [{ name = "sphinx" }] + +[[package]] +name = "cysignals" +version = "1.12.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/be/3dd297fb25113abf40dd5de66088ce6883b62c417caa6b5fc2a84b9d48bf/cysignals-1.12.5.tar.gz", hash = "sha256:8f8ed409043d028b59d063dc4c069cbf12a750534757ce06f38eeac5ff368700", size = 86022, upload-time = "2025-09-24T02:47:35.065Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/7f/4ac0871dfea1e5723db6a8765e340660c6bf789d9d538c10e773c08ab2e0/cysignals-1.12.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7c4074c9a9ae1294abf6a7de224174c2797e3b8f0c86881a04557224ad766bd", size = 220817, upload-time = "2025-09-24T02:47:09.319Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/17b2236fb780081cd95a6609747377c9f5d0bd85fb0d7aa31ee9f5dc531f/cysignals-1.12.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:08dc79fd7470f828d7ae2f70b534a2710d39c1f194ffeb9649fbdff6e6f0bfff", size = 219943, upload-time = "2025-09-24T02:47:10.347Z" }, + { url = "https://files.pythonhosted.org/packages/60/fd/9d84bcd8c0d743b41f22e2ef54125e4e787c401e1ffe569b15a433d089ac/cysignals-1.12.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c8011f72efc59fda3cf72096e7cdfc00f415629252c161c29eb721427a666a8", size = 262680, upload-time = "2025-09-24T02:47:11.35Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e5/6954b9b5d8c843292a58cb091fb52c4a93305681d63e5b48c01d9ff0dead/cysignals-1.12.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eccbcfd762de37daf4a01a0a77ef653561a153c48c2db9104916d36ebbd3cf24", size = 270195, upload-time = "2025-09-24T02:47:12.424Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/cea6ac568ec4c2c9a5d003629346438ec8ceb991a627edc91fa8d24028de/cysignals-1.12.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:741c9bed4ef802c5892f62c6c8ad96390610bcfb617a0250a86c595eecdd13a9", size = 263724, upload-time = "2025-09-24T02:47:13.789Z" }, + { url = "https://files.pythonhosted.org/packages/8f/06/16111451a159266a9b03946498137645cd1fd334331b751b00c55fdc2bd4/cysignals-1.12.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:10e57664e3a2c3e7cdd270b7fa041859b552c2813c195b1247e3c116bf40226b", size = 273469, upload-time = "2025-09-24T02:47:14.785Z" }, + { url = "https://files.pythonhosted.org/packages/63/8a/a50f6df7d3e49f056727b9140521e8588222a904b97d8bca6a81b25b138e/cysignals-1.12.5-cp312-cp312-win_amd64.whl", hash = "sha256:8824990cdf09891ccdd8f5d0f839762948c90535b56d476fcf8c0dddd27ca53b", size = 53672, upload-time = "2025-09-24T02:47:16.127Z" }, + { url = "https://files.pythonhosted.org/packages/20/51/abe5fc0b929c798c7e67f36ea1f0f279e3d3e9549bde8c7e48f272cc48d4/cysignals-1.12.5-cp312-cp312-win_arm64.whl", hash = "sha256:f8e27a442aea569e824b12cd4b8c8599d94e44272e3dfaa56d4ac98215aef7c1", size = 50737, upload-time = "2025-09-24T02:47:16.951Z" }, + { url = "https://files.pythonhosted.org/packages/9c/3e/9873294ae69ab6620a19e225b65b2aaf79b42a0e5c50e55ccda129d493ac/cysignals-1.12.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2131f0a724d3f5c0d6ae11c100641a491b223b075d03aa83c69b1d44736a099", size = 217212, upload-time = "2025-09-24T02:47:18.409Z" }, + { url = "https://files.pythonhosted.org/packages/77/9c/208ba3bad103ed0218d6a225705f2ebc9a886167e0fae5d761c891779057/cysignals-1.12.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:03cb462edcc1ee7b63f2108bbeb89ce04ddca3baeb4d490f26c997ec23f392f1", size = 217008, upload-time = "2025-09-24T02:47:19.495Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ab/ebc8dc495251630832a2572ef9a350ac0d2b7d9608531fbbb65fc61ad6e4/cysignals-1.12.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64895f286cb6e0f070db6ea8c808039fda21b2c3c9876e3486e6f36aa956b557", size = 260584, upload-time = "2025-09-24T02:47:20.564Z" }, + { url = "https://files.pythonhosted.org/packages/95/bc/4aaf0032b7c5c7d3c62e42ce6ffda431778f08ac8f52d701af77ed5db3c1/cysignals-1.12.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0008a7e53f4889f75c5132c06b42723e80ec40f1035be1cbe4d909896e8f55dc", size = 268999, upload-time = "2025-09-24T02:47:21.579Z" }, + { url = "https://files.pythonhosted.org/packages/9c/7d/ef2e2d6a08f3821fd157fe69ecdf921c763645ea6259f557a7712f42b7ee/cysignals-1.12.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800b6b7ad6c45590a2a30d05889378beee9948d8828bc8aafd79694825b595b6", size = 262547, upload-time = "2025-09-24T02:47:22.598Z" }, + { url = "https://files.pythonhosted.org/packages/22/51/0a564cfefe9853ddcfb4b76ab845398471dd4106da29e829be31705db2c1/cysignals-1.12.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c09035afcd3017250e796247f3eaf5e79a9a7090b1e104a962b8eb4c87bf9ebe", size = 271757, upload-time = "2025-09-24T02:47:23.637Z" }, + { url = "https://files.pythonhosted.org/packages/a8/8d/164781b362dca2216916896d2ede197f2496c97fa961ccb6265382e6ad24/cysignals-1.12.5-cp313-cp313-win_amd64.whl", hash = "sha256:7392bbc6a46ee9b1eb973ec994f95f7421257a474c071c56def37c7ce0ea8d87", size = 53494, upload-time = "2025-09-24T02:47:24.922Z" }, + { url = "https://files.pythonhosted.org/packages/53/c8/6e5bb6f96405c41cffef037540a6eb031657e92cb7f2213cf532191f9484/cysignals-1.12.5-cp313-cp313-win_arm64.whl", hash = "sha256:1a2ebb66883be5e493741c5db787d509b2c1f860d32829a184dbc912b33a9f4e", size = 50469, upload-time = "2025-09-24T02:47:25.745Z" }, +] + +[[package]] +name = "cython" +version = "3.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/f6/d762df1f436a0618455d37f4e4c4872a7cd0dcfc8dec3022ee99e4389c69/cython-3.1.4.tar.gz", hash = "sha256:9aefefe831331e2d66ab31799814eae4d0f8a2d246cbaaaa14d1be29ef777683", size = 3190778, upload-time = "2025-09-16T07:20:33.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/51/2939c739cfdc67ab94935a2c4fcc75638afd15e1954552655503a4112e92/cython-3.1.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0d26af46505d0e54fe0f05e7ad089fd0eed8fa04f385f3ab88796f554467bcb9", size = 3062976, upload-time = "2025-09-16T07:22:20.517Z" }, + { url = "https://files.pythonhosted.org/packages/eb/bd/a84de57fd01017bf5dba84a49aeee826db21112282bf8d76ab97567ee15d/cython-3.1.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66ac8bb5068156c92359e3f0eefa138c177d59d1a2e8a89467881fa7d06aba3b", size = 2970701, upload-time = "2025-09-16T07:22:22.644Z" }, + { url = "https://files.pythonhosted.org/packages/71/79/a09004c8e42f5be188c7636b1be479cdb244a6d8837e1878d062e4e20139/cython-3.1.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2e42714faec723d2305607a04bafb49a48a8d8f25dd39368d884c058dbcfbc", size = 3387730, upload-time = "2025-09-16T07:22:24.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/bd/979f8c59e247f562642f3eb98a1b453530e1f7954ef071835c08ed2bf6ba/cython-3.1.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0fd655b27997a209a574873304ded9629de588f021154009e8f923475e2c677", size = 3167289, upload-time = "2025-09-16T07:22:26.35Z" }, + { url = "https://files.pythonhosted.org/packages/34/f8/0b98537f0b4e8c01f76d2a6cf75389987538e4d4ac9faf25836fd18c9689/cython-3.1.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9def7c41f4dc339003b1e6875f84edf059989b9c7f5e9a245d3ce12c190742d9", size = 3321099, upload-time = "2025-09-16T07:22:27.957Z" }, + { url = "https://files.pythonhosted.org/packages/f3/39/437968a2e7c7f57eb6e1144f6aca968aa15fbbf169b2d4da5d1ff6c21442/cython-3.1.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:196555584a8716bf7e017e23ca53e9f632ed493f9faa327d0718e7551588f55d", size = 3179897, upload-time = "2025-09-16T07:22:30.014Z" }, + { url = "https://files.pythonhosted.org/packages/2c/04/b3f42915f034d133f1a34e74a2270bc2def02786f9b40dc9028fbb968814/cython-3.1.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7fff0e739e07a20726484b8898b8628a7b87acb960d0fc5486013c6b77b7bb97", size = 3400936, upload-time = "2025-09-16T07:22:31.705Z" }, + { url = "https://files.pythonhosted.org/packages/21/eb/2ad9fa0896ab6cf29875a09a9f4aaea37c28b79b869a013bf9b58e4e652e/cython-3.1.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2754034fa10f95052949cd6b07eb2f61d654c1b9cfa0b17ea53a269389422e8", size = 3332131, upload-time = "2025-09-16T07:22:33.32Z" }, + { url = "https://files.pythonhosted.org/packages/3c/bf/f19283f8405e7e564c3353302a8665ea2c589be63a8e1be1b503043366a9/cython-3.1.4-cp312-cp312-win32.whl", hash = "sha256:2e0808ff3614a1dbfd1adfcbff9b2b8119292f1824b3535b4a173205109509f8", size = 2487672, upload-time = "2025-09-16T07:22:35.227Z" }, + { url = "https://files.pythonhosted.org/packages/30/bf/32150a2e6c7b50b81c5dc9e942d41969400223a9c49d04e2ed955709894c/cython-3.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:f262b32327b6bce340cce5d45bbfe3972cb62543a4930460d8564a489f3aea12", size = 2705348, upload-time = "2025-09-16T07:22:37.922Z" }, + { url = "https://files.pythonhosted.org/packages/24/10/1acc34f4d2d14de38e2d3ab4795ad1c8f547cebc2d9e7477a49a063ba607/cython-3.1.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ab549d0fc187804e0f14fc4759e4b5ad6485ffc01554b2f8b720cc44aeb929cd", size = 3051524, upload-time = "2025-09-16T07:22:40.607Z" }, + { url = "https://files.pythonhosted.org/packages/04/85/8457a78e9b9017a4fb0289464066ff2e73c5885f1edb9c1b9faaa2877fe2/cython-3.1.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:52eae5d9bcc515441a436dcae2cbadfd00c5063d4d7809bd0178931690c06a76", size = 2958862, upload-time = "2025-09-16T07:22:42.646Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a8/42989748b63ec56c5b950fd26ec01fc77f9cf72dc318eb2eee257a6b652c/cython-3.1.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6f06345cfa583dd17fff1beedb237853689b85aa400ea9e0db7e5265f3322d15", size = 3364296, upload-time = "2025-09-16T07:22:44.444Z" }, + { url = "https://files.pythonhosted.org/packages/98/9d/b27d5d402552932875f2b8f795385dabd27525a8a6645010c876fe84a0f9/cython-3.1.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f5d915556c757212cb8ddd4e48c16f2ab481dbb9a76f5153ab26f418c3537eb5", size = 3154391, upload-time = "2025-09-16T07:22:46.852Z" }, + { url = "https://files.pythonhosted.org/packages/65/55/742737e40f7a3f1963440d66322b5fa93844762dd7a3a23d9b5b1d0d594e/cython-3.1.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c3f3bb603f28b3c1df66baaa5cdbf6029578552b458f1d321bae23b87f6c3199", size = 3305883, upload-time = "2025-09-16T07:22:48.55Z" }, + { url = "https://files.pythonhosted.org/packages/98/3f/0baecd7ac0fac2dbb47acd7f0970c298f38d0504774c5552cf6224bdf3e6/cython-3.1.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7aff230893ee1044e7bc98d313c034ead70a3dd54d4d22e89ca1734540d94084", size = 3170437, upload-time = "2025-09-16T07:22:50.213Z" }, + { url = "https://files.pythonhosted.org/packages/74/18/1ec53e2cf10a8064c7faa305b105b9c45af619ee30a6f1f7eb91efbb304b/cython-3.1.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8e83f114c04f72f85591ddb0b28f08ab2e40d250c26686d6509c0f70a9e2ca34", size = 3377458, upload-time = "2025-09-16T07:22:52.192Z" }, + { url = "https://files.pythonhosted.org/packages/bd/8c/3d0839cf0b315157974bf283d4bd658f5c30277091ad34c093f286c59e0f/cython-3.1.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8096394960d38b793545753b73781bc0ec695f0b8c22454431704b297e296045", size = 3318723, upload-time = "2025-09-16T07:22:54.322Z" }, + { url = "https://files.pythonhosted.org/packages/c6/05/67b4de710a3109030d868e23d5dccf35559afa4c089b4c0aa9e22ffda1f1/cython-3.1.4-cp313-cp313-win32.whl", hash = "sha256:4e7c726ac753ca1a5aa30286cbadcd10ed4b4312ea710a8a16bb908d41e9c059", size = 2481433, upload-time = "2025-09-16T07:22:56.409Z" }, + { url = "https://files.pythonhosted.org/packages/89/ef/f179b5a46185bc5550c07b328d687ee32251963a3a93e869b75fbf97181c/cython-3.1.4-cp313-cp313-win_amd64.whl", hash = "sha256:f2ee2bb77943044f301cec04d0b51d8e3810507c9c250d6cd079a3e2d6ba88f2", size = 2703057, upload-time = "2025-09-16T07:22:57.994Z" }, + { url = "https://files.pythonhosted.org/packages/38/85/f1380e8370b470b218e452ba3995555524e3652f026333e6bad6c68770b5/cython-3.1.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c7258739d5560918741cb040bd85ba7cc2f09d868de9116a637e06714fec1f69", size = 3045864, upload-time = "2025-09-16T07:22:59.854Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/54c7bc78df1e55ac311054cb2fd33908f23b8a6f350c30defeca416d8077/cython-3.1.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b2d522ee8d3528035e247ee721fb40abe92e9ea852dc9e48802cec080d5de859", size = 2967105, upload-time = "2025-09-16T07:23:01.666Z" }, + { url = "https://files.pythonhosted.org/packages/02/02/89f70e71972f796863429b159c8e8e858b85bedbc9c747d167a5c6f6417e/cython-3.1.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a4e0560baeb56c29d7d8d693a050dd4d2ed922d8d7c66f5c5715c6f2be84e903", size = 3363386, upload-time = "2025-09-16T07:23:03.39Z" }, + { url = "https://files.pythonhosted.org/packages/2a/34/eda836ae260013d4dd1c7aaa8dd6f7d7862206ba3354db5d8f55a8f6ef67/cython-3.1.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4223cacc81cba0df0f06f79657c5d6286e153b9a9b989dad1cdf4666f618c073", size = 3192314, upload-time = "2025-09-16T07:23:05.354Z" }, + { url = "https://files.pythonhosted.org/packages/7e/fa/db8224f7fe7ec1ebdab0b5e71b5a8269c112645c4eac2464ef0735bb395e/cython-3.1.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ff4d1f159edee6af38572318681388fbd6448b0d08b9a47494aaf0b698e93394", size = 3312222, upload-time = "2025-09-16T07:23:07.066Z" }, + { url = "https://files.pythonhosted.org/packages/62/09/419262657800dee7202a76956cd52896a6e8793bbbecc2592a4ebba2e034/cython-3.1.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2537c53071a9a124e0bc502a716e1930d9bb101e94c26673016cf1820e4fdbd1", size = 3208798, upload-time = "2025-09-16T07:23:08.758Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d8/f140c7b9356a29660dc05591272e33062df964b9d1a072d09e89ade41087/cython-3.1.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:85416717c529fb5ccf908464657a5187753e76d7b6ffec9b1c2d91544f6c3628", size = 3379662, upload-time = "2025-09-16T07:23:10.511Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e8/83cf9a9cf64cbfe4eaf3987a633be08243f838b7d12e5739831297b77311/cython-3.1.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:18882e2f5c0e0c25f9c44f16f2fb9c48f33988885c5f9eae2856f10c6f089ffa", size = 3324255, upload-time = "2025-09-16T07:23:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f8/f2033044687cf6296275fa71cdf63a247d3646a3e276aa002e65bf505f46/cython-3.1.4-cp314-cp314-win32.whl", hash = "sha256:8ef8deadc888eaf95e5328fc176fb6c37bccee1213f07517c6ea55b5f817c457", size = 2503665, upload-time = "2025-09-16T07:23:14.372Z" }, + { url = "https://files.pythonhosted.org/packages/04/57/7af75a803d55610d570d7b7a0fdc2bfd82fae030c728089cc628562d67f9/cython-3.1.4-cp314-cp314-win_amd64.whl", hash = "sha256:acb99ddec62ba1ea5de0e0087760fa834ec42c94f0488065a4f1995584e8e94e", size = 2734608, upload-time = "2025-09-16T07:23:16.025Z" }, + { url = "https://files.pythonhosted.org/packages/7c/24/f7351052cf9db771fe4f32fca47fd66e6d9b53d8613b17faf7d130a9d553/cython-3.1.4-py3-none-any.whl", hash = "sha256:d194d95e4fa029a3f6c7d46bdd16d973808c7ea4797586911fdb67cb98b1a2c6", size = 1227541, upload-time = "2025-09-16T07:20:29.595Z" }, +] + +[[package]] +name = "dependency-groups" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/55/f054de99871e7beb81935dea8a10b90cd5ce42122b1c3081d5282fdb3621/dependency_groups-1.3.1.tar.gz", hash = "sha256:78078301090517fd938c19f64a53ce98c32834dfe0dee6b88004a569a6adfefd", size = 10093, upload-time = "2025-05-02T00:34:29.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/c7/d1ec24fb280caa5a79b6b950db565dab30210a66259d17d5bb2b3a9f878d/dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030", size = 8664, upload-time = "2025-05-02T00:34:27.085Z" }, +] + +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, +] + +[[package]] +name = "filelock" +version = "3.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, +] + +[[package]] +name = "humanize" +version = "4.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/1d/3062fcc89ee05a715c0b9bfe6490c00c576314f27ffee3a704122c6fd259/humanize-4.13.0.tar.gz", hash = "sha256:78f79e68f76f0b04d711c4e55d32bebef5be387148862cb1ef83d2b58e7935a0", size = 81884, upload-time = "2025-08-25T09:39:20.04Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/c7/316e7ca04d26695ef0635dc81683d628350810eb8e9b2299fc08ba49f366/humanize-4.13.0-py3-none-any.whl", hash = "sha256:b810820b31891813b1673e8fec7f1ed3312061eab2f26e3fa192c393d11ed25f", size = 128869, upload-time = "2025-08-25T09:39:18.54Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "meson" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/07/b48592d325cb86682829f05216e4efb2dc881762b8f1bafb48b57442307a/meson-1.9.1-py3-none-any.whl", hash = "sha256:f824ab770c041a202f532f69e114c971918ed2daff7ea56583d80642564598d0", size = 1030356, upload-time = "2025-09-22T18:39:37.458Z" }, +] + +[[package]] +name = "meson-python" +version = "0.18.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "meson" }, + { name = "packaging" }, + { name = "pyproject-metadata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/bd/fdb26366443620f1a8a4d4ec7bfa37d1fbbe7bf737b257c205bbcf95ba95/meson_python-0.18.0.tar.gz", hash = "sha256:c56a99ec9df669a40662fe46960321af6e4b14106c14db228709c1628e23848d", size = 95630, upload-time = "2025-05-05T10:13:56.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/58/66db620a8a7ccb32633de9f403fe49f1b63c68ca94e5c340ec5cceeb9821/meson_python-0.18.0-py3-none-any.whl", hash = "sha256:3b0fe051551cc238f5febb873247c0949cd60ded556efa130aa57021804868e2", size = 28420, upload-time = "2025-05-05T10:13:55.218Z" }, +] + +[[package]] +name = "ninja" +version = "1.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/73/79a0b22fc731989c708068427579e840a6cf4e937fe7ae5c5d0b7356ac22/ninja-1.13.0.tar.gz", hash = "sha256:4a40ce995ded54d9dc24f8ea37ff3bf62ad192b547f6c7126e7e25045e76f978", size = 242558, upload-time = "2025-08-11T15:10:19.421Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/74/d02409ed2aa865e051b7edda22ad416a39d81a84980f544f8de717cab133/ninja-1.13.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:fa2a8bfc62e31b08f83127d1613d10821775a0eb334197154c4d6067b7068ff1", size = 310125, upload-time = "2025-08-11T15:09:50.971Z" }, + { url = "https://files.pythonhosted.org/packages/8e/de/6e1cd6b84b412ac1ef327b76f0641aeb5dcc01e9d3f9eee0286d0c34fd93/ninja-1.13.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3d00c692fb717fd511abeb44b8c5d00340c36938c12d6538ba989fe764e79630", size = 177467, upload-time = "2025-08-11T15:09:52.767Z" }, + { url = "https://files.pythonhosted.org/packages/c8/83/49320fb6e58ae3c079381e333575fdbcf1cca3506ee160a2dcce775046fa/ninja-1.13.0-py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:be7f478ff9f96a128b599a964fc60a6a87b9fa332ee1bd44fa243ac88d50291c", size = 187834, upload-time = "2025-08-11T15:09:54.115Z" }, + { url = "https://files.pythonhosted.org/packages/56/c7/ba22748fb59f7f896b609cd3e568d28a0a367a6d953c24c461fe04fc4433/ninja-1.13.0-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:60056592cf495e9a6a4bea3cd178903056ecb0943e4de45a2ea825edb6dc8d3e", size = 202736, upload-time = "2025-08-11T15:09:55.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/22/d1de07632b78ac8e6b785f41fa9aad7a978ec8c0a1bf15772def36d77aac/ninja-1.13.0-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1c97223cdda0417f414bf864cfb73b72d8777e57ebb279c5f6de368de0062988", size = 179034, upload-time = "2025-08-11T15:09:57.394Z" }, + { url = "https://files.pythonhosted.org/packages/ed/de/0e6edf44d6a04dabd0318a519125ed0415ce437ad5a1ec9b9be03d9048cf/ninja-1.13.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fb46acf6b93b8dd0322adc3a4945452a4e774b75b91293bafcc7b7f8e6517dfa", size = 180716, upload-time = "2025-08-11T15:09:58.696Z" }, + { url = "https://files.pythonhosted.org/packages/54/28/938b562f9057aaa4d6bfbeaa05e81899a47aebb3ba6751e36c027a7f5ff7/ninja-1.13.0-py3-none-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4be9c1b082d244b1ad7ef41eb8ab088aae8c109a9f3f0b3e56a252d3e00f42c1", size = 146843, upload-time = "2025-08-11T15:10:00.046Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fb/d06a3838de4f8ab866e44ee52a797b5491df823901c54943b2adb0389fbb/ninja-1.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:6739d3352073341ad284246f81339a384eec091d9851a886dfa5b00a6d48b3e2", size = 154402, upload-time = "2025-08-11T15:10:01.657Z" }, + { url = "https://files.pythonhosted.org/packages/31/bf/0d7808af695ceddc763cf251b84a9892cd7f51622dc8b4c89d5012779f06/ninja-1.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11be2d22027bde06f14c343f01d31446747dbb51e72d00decca2eb99be911e2f", size = 552388, upload-time = "2025-08-11T15:10:03.349Z" }, + { url = "https://files.pythonhosted.org/packages/9d/70/c99d0c2c809f992752453cce312848abb3b1607e56d4cd1b6cded317351a/ninja-1.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:aa45b4037b313c2f698bc13306239b8b93b4680eb47e287773156ac9e9304714", size = 472501, upload-time = "2025-08-11T15:10:04.735Z" }, + { url = "https://files.pythonhosted.org/packages/9f/43/c217b1153f0e499652f5e0766da8523ce3480f0a951039c7af115e224d55/ninja-1.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f8e1e8a1a30835eeb51db05cf5a67151ad37542f5a4af2a438e9490915e5b72", size = 638280, upload-time = "2025-08-11T15:10:06.512Z" }, + { url = "https://files.pythonhosted.org/packages/8c/45/9151bba2c8d0ae2b6260f71696330590de5850e5574b7b5694dce6023e20/ninja-1.13.0-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:3d7d7779d12cb20c6d054c61b702139fd23a7a964ec8f2c823f1ab1b084150db", size = 642420, upload-time = "2025-08-11T15:10:08.35Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/95752eb635bb8ad27d101d71bef15bc63049de23f299e312878fc21cb2da/ninja-1.13.0-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:d741a5e6754e0bda767e3274a0f0deeef4807f1fec6c0d7921a0244018926ae5", size = 585106, upload-time = "2025-08-11T15:10:09.818Z" }, + { url = "https://files.pythonhosted.org/packages/c1/31/aa56a1a286703800c0cbe39fb4e82811c277772dc8cd084f442dd8e2938a/ninja-1.13.0-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:e8bad11f8a00b64137e9b315b137d8bb6cbf3086fbdc43bf1f90fd33324d2e96", size = 707138, upload-time = "2025-08-11T15:10:11.366Z" }, + { url = "https://files.pythonhosted.org/packages/34/6f/5f5a54a1041af945130abdb2b8529cbef0cdcbbf9bcf3f4195378319d29a/ninja-1.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b4f2a072db3c0f944c32793e91532d8948d20d9ab83da9c0c7c15b5768072200", size = 581758, upload-time = "2025-08-11T15:10:13.295Z" }, + { url = "https://files.pythonhosted.org/packages/95/97/51359c77527d45943fe7a94d00a3843b81162e6c4244b3579fe8fc54cb9c/ninja-1.13.0-py3-none-win32.whl", hash = "sha256:8cfbb80b4a53456ae8a39f90ae3d7a2129f45ea164f43fadfa15dc38c4aef1c9", size = 267201, upload-time = "2025-08-11T15:10:15.158Z" }, + { url = "https://files.pythonhosted.org/packages/29/45/c0adfbfb0b5895aa18cec400c535b4f7ff3e52536e0403602fc1a23f7de9/ninja-1.13.0-py3-none-win_amd64.whl", hash = "sha256:fb8ee8719f8af47fed145cced4a85f0755dd55d45b2bddaf7431fa89803c5f3e", size = 309975, upload-time = "2025-08-11T15:10:16.697Z" }, + { url = "https://files.pythonhosted.org/packages/df/93/a7b983643d1253bb223234b5b226e69de6cda02b76cdca7770f684b795f5/ninja-1.13.0-py3-none-win_arm64.whl", hash = "sha256:3c0b40b1f0bba764644385319028650087b4c1b18cdfa6f45cb39a3669b81aa9", size = 290806, upload-time = "2025-08-11T15:10:18.018Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "patchelf" +version = "0.17.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/a3/fdd3fa938c864aa2f11dd0b7f08befeda983d2dcdee44da493c6977a653f/patchelf-0.17.2.4.tar.gz", hash = "sha256:970ee5cd8af33e5ea2099510b2f9013fa1b8d5cd763bf3fd3961281c18101a09", size = 149629, upload-time = "2025-07-23T21:16:32.071Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/a7/8c4f86c78ec03db954d05fd9c57a114cc3a172a2d3e4a8b949cd5ff89471/patchelf-0.17.2.4-py3-none-macosx_10_9_universal2.whl", hash = "sha256:343bb1b94e959f9070ca9607453b04390e36bbaa33c88640b989cefad0aa049e", size = 184436, upload-time = "2025-07-23T21:16:20.578Z" }, + { url = "https://files.pythonhosted.org/packages/7e/19/f7821ef31aab01fa7dc8ebe697ece88ec4f7a0fdd3155dab2dfee4b00e5c/patchelf-0.17.2.4-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:d9b35ebfada70c02679ad036407d9724ffe1255122ba4ac5e4be5868618a5689", size = 482846, upload-time = "2025-07-23T21:16:23.73Z" }, + { url = "https://files.pythonhosted.org/packages/d1/50/107fea848ecfd851d473b079cab79107487d72c4c3cdb25b9d2603a24ca2/patchelf-0.17.2.4-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:2931a1b5b85f3549661898af7bf746afbda7903c7c9a967cfc998a3563f84fad", size = 477811, upload-time = "2025-07-23T21:16:25.145Z" }, + { url = "https://files.pythonhosted.org/packages/89/a9/a9a2103e159fd65bffbc21ecc5c8c36e44eb34fe53b4ef85fb6d08c2a635/patchelf-0.17.2.4-py3-none-manylinux2014_armv7l.manylinux_2_17_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:ae44cb3c857d50f54b99e5697aa978726ada33a8a6129d4b8b7ffd28b996652d", size = 431226, upload-time = "2025-07-23T21:16:26.765Z" }, + { url = "https://files.pythonhosted.org/packages/87/93/897d612f6df7cfd987bdf668425127efeff8d8e4ad8bfbab1c69d2a0d861/patchelf-0.17.2.4-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:680a266a70f60a7a4f4c448482c5bdba80cc8e6bb155a49dcc24238ba49927b0", size = 540276, upload-time = "2025-07-23T21:16:27.983Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b8/2b92d11533482bac9ee989081d6880845287751b5f528adbd6bb27667fbd/patchelf-0.17.2.4-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.musllinux_1_1_s390x.whl", hash = "sha256:d842b51f0401460f3b1f3a3a67d2c266a8f515a5adfbfa6e7b656cb3ac2ed8bc", size = 596632, upload-time = "2025-07-23T21:16:29.253Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/975d4bdb418f942b53e6187b95bd9e0d5e0488b7bc214685a1e43e2c2751/patchelf-0.17.2.4-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:7076d9e127230982e20a81a6e2358d3343004667ba510d9f822d4fdee29b0d71", size = 508281, upload-time = "2025-07-23T21:16:30.865Z" }, +] + +[[package]] +name = "pkgconf" +version = "2.4.3.post2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "os_name == 'nt'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/4f/27b39de8c295efed8fbc32517ee07e4b26e9eb95d0fbf8b5d698e76d7412/pkgconf-2.4.3.post2.tar.gz", hash = "sha256:73d966e18f75e89da54c83a65effc8c2e9b7316553a060c8293ee527a0834c10", size = 144454, upload-time = "2025-06-08T10:19:41.581Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/08/0a89947c84804f1646e2ba0f836bc535f325b6a1d2e8c5bdcdadeb8c8916/pkgconf-2.4.3.post2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:7c90084ac070447370240f2df664786726ab2a399e51677d3dba10cf7cd0cc36", size = 47873, upload-time = "2025-06-08T10:19:16.404Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f3/202c5a410fd432d02cc32f070fa82382c3c312dbe23b62a840b41e1d273e/pkgconf-2.4.3.post2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e9adb489a4a52dad6f6029d5dffd2d4e4262b5b9387ae34869ef5576ce7834e9", size = 46329, upload-time = "2025-06-08T10:19:18.139Z" }, + { url = "https://files.pythonhosted.org/packages/55/81/60669fa13e37ae3cab204d5e82d1c908c56f6037651116e5e29d20bf0546/pkgconf-2.4.3.post2-py3-none-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:ae888298e699e5ff91ada94d304f2b6bac1b83f0b7c3cad9fcd07032ff511106", size = 62144, upload-time = "2025-06-08T10:19:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/78/c7/55c1d732a026b8e2a7ba23d730a1484063f7e85e19372045093db58feed3/pkgconf-2.4.3.post2-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:94d4e41290fdc5293b6ac19c4bbd1a1a934866b6ca23c1393275a810e2cc10d0", size = 58855, upload-time = "2025-06-08T10:19:21.349Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b8/4536a1647d7cad90a2decc486882e6eb5d6c6da4d233214ae3b922a81c8a/pkgconf-2.4.3.post2-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c01f8e33fdf236c2365cd98e875eb98754d9868c52e168bf14a9fca818064695", size = 58266, upload-time = "2025-06-08T10:19:22.939Z" }, + { url = "https://files.pythonhosted.org/packages/29/5a/03ebbacdc3129c21b822cb7a3b48894b8decd0dc2efba7d3bfa783991592/pkgconf-2.4.3.post2-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b34a33281d80b5d6c7ffc31aaeb58d590a6e9082fc09361b80b491d55c1b679", size = 68586, upload-time = "2025-06-08T10:19:24.53Z" }, + { url = "https://files.pythonhosted.org/packages/52/fd/5f8666a58c2a7d8565a64434ed833e2eac6a733eb7e133eafb36001e7e9d/pkgconf-2.4.3.post2-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:aef6dad009f6627c9dcc8c25a7f1b40d273b8c8bf6035a380093406906b4df68", size = 62255, upload-time = "2025-06-08T10:19:25.741Z" }, + { url = "https://files.pythonhosted.org/packages/21/a4/ce37c5b42e59dc4f157553fa0413a0b12e2549b586193bc2429a3d637760/pkgconf-2.4.3.post2-py3-none-manylinux_2_27_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bc7de745a75ae453118944bb069cc8cc4175c6b1c96c0263537826c6c87e142", size = 52943, upload-time = "2025-06-08T10:19:27.35Z" }, + { url = "https://files.pythonhosted.org/packages/1c/92/18de0b35344f6fd63a1c79b497cdf907276c67967ef5958ec0009dbcb13b/pkgconf-2.4.3.post2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:9e4eba8ff57743113c6f1ae1a3ca24dab775ef669fc5889dafff76e7cdf3155d", size = 59671, upload-time = "2025-06-08T10:19:28.635Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ba/4217032c3f98b1751205659d96b2452c0ef08cfcc6956d504ad05c29795c/pkgconf-2.4.3.post2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:876f061f930b36a5e299103d8145e39ca02b612d85984be33af6a0ccd9c464d5", size = 56607, upload-time = "2025-06-08T10:19:30.23Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d0/3deff09bc801aa0214053fa147e41c685b1c5ce974bfd20c6ceeb7333c20/pkgconf-2.4.3.post2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f38b1081b06860edce8926d67899dfe7b85db03723b3fa18b3e12efa5dd94395", size = 64167, upload-time = "2025-06-08T10:19:31.435Z" }, + { url = "https://files.pythonhosted.org/packages/1d/e1/ec39d2166a07899c4ca0c608139496b0f6044deb50aedb1da687b173d933/pkgconf-2.4.3.post2-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:95ddd0d06dd50418a04613fae5a6e0c46cc06329de006f1513ea6f7bdc40807b", size = 69318, upload-time = "2025-06-08T10:19:32.997Z" }, + { url = "https://files.pythonhosted.org/packages/14/f4/71f16620dd87ce7e8ec4ea8dcd17c0075d72ed153cc6105d1949e085ceb6/pkgconf-2.4.3.post2-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:f7f616a789c18ce9aebb5fc4cfdc48577575f2ab7df803b4df06a5298db9bdfa", size = 62008, upload-time = "2025-06-08T10:19:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/a1/a9/48ea4d861bca750ed6a38b81e4e82d5f53c24f3430bcdec49e30d8ee39fc/pkgconf-2.4.3.post2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:201696a9c7d60668cab62a706ea159a560c08700a8690e70abc2e572a955752d", size = 60560, upload-time = "2025-06-08T10:19:36.194Z" }, + { url = "https://files.pythonhosted.org/packages/e9/4b/8c6e6be7bc9dc2daf885512b28723590a55fdebd68004b4083935949e984/pkgconf-2.4.3.post2-py3-none-win32.whl", hash = "sha256:90ee5b800865ecbdaf4e9302b06091b52d5528831c3e45f344a7287879d7adfa", size = 49753, upload-time = "2025-06-08T10:19:37.448Z" }, + { url = "https://files.pythonhosted.org/packages/05/5b/2344be3846958600757697178844d681b38b457cccd2ea524a200895245b/pkgconf-2.4.3.post2-py3-none-win_amd64.whl", hash = "sha256:e11231d852a230dd35e61ca79c0d89136a6c9ccf7654a2a076384af01d5eb902", size = 49753, upload-time = "2025-06-08T10:19:39.033Z" }, + { url = "https://files.pythonhosted.org/packages/56/76/75cb3e62b23628251f00574a6631c9c479bf272a0f6931e0c16c5247dc8d/pkgconf-2.4.3.post2-py3-none-win_arm64.whl", hash = "sha256:b1d137097771fcbcfc94926ea795244248833c9fe46c9631ea88bf156dc7b1cc", size = 44448, upload-time = "2025-06-08T10:19:40.279Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pyelftools" +version = "0.32" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/ab/33968940b2deb3d92f5b146bc6d4009a5f95d1d06c148ea2f9ee965071af/pyelftools-0.32.tar.gz", hash = "sha256:6de90ee7b8263e740c8715a925382d4099b354f29ac48ea40d840cf7aa14ace5", size = 15047199, upload-time = "2025-02-19T14:20:05.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/43/700932c4f0638c3421177144a2e86448c0d75dbaee2c7936bda3f9fd0878/pyelftools-0.32-py3-none-any.whl", hash = "sha256:013df952a006db5e138b1edf6d8a68ecc50630adbd0d83a2d41e7f846163d738", size = 188525, upload-time = "2025-02-19T14:19:59.919Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228, upload-time = "2024-09-29T09:24:13.293Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" }, +] + +[[package]] +name = "pyproject-metadata" +version = "0.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/ae/5fa065b049e97f96880de0611dbba513f0ee313b6edd0a64664c7b46a8e8/pyproject_metadata-0.9.1.tar.gz", hash = "sha256:b8b2253dd1b7062b78cf949a115f02ba7fa4114aabe63fa10528e9e1a954a816", size = 38415, upload-time = "2025-03-10T22:15:11.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b1/8e63033b259e0a4e40dd1ec4a9fee17718016845048b43a36ec67d62e6fe/pyproject_metadata-0.9.1-py3-none-any.whl", hash = "sha256:ee5efde548c3ed9b75a354fc319d5afd25e9585fa918a34f62f904cc731973ad", size = 18829, upload-time = "2025-03-10T22:15:09.632Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "roman-numerals-py" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017, upload-time = "2025-02-22T07:34:54.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742, upload-time = "2025-02-22T07:34:52.422Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "sphinx" +version = "8.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals-py" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "wheel" +version = "0.45.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545, upload-time = "2024-11-23T00:18:23.513Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" }, +]